话说傲娇的链表文艺青年
昨天花了一下午的时间写我的链表,写的有点晕,下面来总结一下链表的小知识点:
一:链表VS顺序表
线性表的存储有两种方式:顺序存储和链式存储。顺序存储相当于数组的存储,在开辟的存储空间中有顺序地存储元素,这一特点使我们可以随机存取表中的任一结点,但它也使得插入和删除操作会移动大量的结点.,为避免大量结点的移动,我们采用线性表的另一种存储方式:链式存储结构,简称为链表。
顺序存储类似于一种静态的存储,顺序表中存储的一样结构的东西。一切都是板上钉钉的事,我只需要知道顺序表存储的首地址我就可以知道整个顺序表中的任何一个元素的存储地址。所以说顺序存储好像一个贤惠的妻子,中规中矩,一些都是井井有条的;它也好似人类的群居现象,物以类聚,人以群分,群中的人紧紧联系,不可分离。
链式存储相当于一种动态存储,每一条链表好像小女孩手中的一串玛瑙项链,我们是用线串在一起的,你是我的前面一粒珠子,他是我的后面一串珠子,一旦某一个线断了,我就在也找不到我后面的珠子去哪里了,但是只要给我一根连接的线,我又能自由地组合成一串美丽的玛瑙项链。所以,链表是一个追求自由的,随性的文艺青年,享受孤独又容易相处!
那么到底选用哪一种存储方式呢?这个就要具体问题具体分析了!
就效率来说:
顺序存储:添加元素, 删除元素的效率低;修改元素,获取元素的效率高。
链式存储:添加元素,删除元素效率高;修改元素,获取元素效率低。
二:实现链表的思路:
1.节点类:属性有:数据(元素),下一个节点
2.定义一个接口:定义链表的功能:增删改查,取得链表的长度,在某一个位置插入一个元素,判断链表是否存在等
3.实现接口的类:链表类
属性:头节点,尾节点,链表的长度
方法:继承接口,实现接口的所有方法
4.注意:用泛型实现链表更加方便
三:链表的实现:
链表的实现要注意的其实只有两点:一是节点的插入,一是节点的删除。
节点的插入:
节点的删除:
示例代码:
1.节点类:
public class Node<E> { //数据(元素) private E data; //下一个节点 private Node<E> next; //链表的长度 private int size; public Node(){} public Node(E e){ this.data=e; } public E getData() { return data; } public void setData(E data) { this.data = data; } public Node<E> getNext() { return next; } public void setNext(Node<E> next) { this.next = next; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } }
2.接口类:
public interface MyList<E> { //向链表中加入一个对象 public void add(E e); //取得链表中指定位置的一个对象 public E get(int index); //取得链表的长度 public int size(); //删除一个对象 public void delete(E data); //修改一个对象 public void change(E e,int index); //在某一个位置插入一个元素 public void insert(E e,int index); //判断链表是否存在 public Boolean isexit(); }
3.链表类:
public class SList<E> implements MyList<E> { // 链表的属性 private Node<E> head;// 头节点 private Node<E> tail;// 尾节点 private static int size;//链表的长度 public int getSize() { return size; } public void setSize(int size) { SList.size = size; } private static SList<String> st; Node<E> newNode; public static void main(String[] args) { st = new SList<>(); st.add("i walk like"); st.add("a worm"); st.add("but"); st.add("i never give up"); st.add("!"); System.out.println("判断链表是否存在:"); st.isexit(); System.out.println("添加了"+st.getSize()+"个节点:"); printList(); System.out.println("将第三个元素改为however"); st.change("however",3); printList(); System.out.println("将i never give up删除"); st.delete("i never give up"); printList(); System.out.println("在第二个节点后面插入一个元素:"); st.insert("My favorite words!", 3); printList(); System.out.println("当前链表的长度是:"+st.size()); } //打印链表 public static void printList(){ for (int i = 0; i <st.getSize(); i++) { System.out.println(st.get(i)); } } // 链表的方法 @Override public void add(E e) { /* * 分情况考虑: 1.这是个空队列 2.已经有了头节点 */ //新建一个节点 Node<E> newNode = new Node<E>(e); //1:分情况考虑 添加第一个元素,和第一个元素已经存在的情况 if(size > 0){ //将尾节点的下一个节点变为新节点 tail.setNext(newNode); }else{ //创建头结点 head = new Node<E>(); //头结点的下一个节点为新节点 head.setNext(newNode); } //把新节点变为尾节点 tail = newNode; //个数+1 size++; } // 获取一个元素 @Override public E get(int index){ //定义节点为第一个节点 Node<E> node = head.getNext(); for(int i=0; i<index; i++){ //将节点变为下一个节点 node = node.getNext(); } return node.getData(); } @Override public int size() { return SList.size; } // 删除一个元素 @Override public void delete(E data){ //删除某一节点 Node<E> curr=head.getNext(),prev=null; boolean b=false; while(curr!=null){ if(curr.getData().equals(data)){ //判断是什么节点 if(curr==head){ //如果删除的是头节点 head=curr.getNext(); b=true; size=size-1; return; } if(curr==tail){ //如果删除的是尾节点 tail=prev; prev.setNext(null); b=true; size=size-1; return; } else{ // 如果删除的是中间节点(即非头节点或非尾节点) prev.setNext(curr.getNext()); b=true; size=size-1; return; } } prev=curr; curr=curr.getNext(); } if(b==false){ System.out.println(' '+"没有这个数据"); } } // 修改一个元素 @Override public void change(E e,int index) { //定义节点为第一个节点 Node<E> node = head.getNext(); for(int i=0; i<index;i++){ if(i==index-1){ node.setData(e); }else{ //将节点变为下一个节点 node = node.getNext(); } } } //在某一个指定的位置插入一个节点 @Override public void insert(E e, int index) { //定义节点为第一个节点 Node<E> node = head.getNext(); for(int i=0; i<index; i++){ if(i==index-1){//找到了要插入的节点位置 Node<E> inNode=new Node<E>(e); inNode.setData(e); inNode.setNext(node.getNext()); node.setNext(inNode); size++; }else //将节点变为下一个节点 node = node.getNext(); } } //判断链表是否存在 @Override public Boolean isexit() { if(st.getSize()>0){ System.out.println("链表存在!"); return true; }else{ System.out.println("链表不存在!"); return false;} } }
效果展示:
练习: