什么是链表?
链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的
从上图可以看出来,链式结构在逻辑上是连续的,但是在物理上不一定连续
链式中的节点一般都是在堆中申请出来的
从堆上申请出来的空间,是按照一定策略来分配的,两次申请出来的空间可能连续,也可能不连续
链表分了很多种:
不带头 单向 非循环 链表
不带头 单项 循环 链表
不带头 双向 非循环 链表
不带头 双向 循环 链表
带头 单向 非循环 链表
带头 单项 循环 链表
带头 双向 非循环 链表
带头 双向 循环 链表
一共八种,本篇文章主要说到不带头 单项 非循环链表 这种也是最常见的
本篇文章主要对下列接口中的方法进行实现,文章末有全部代码
public interface Ilist {//头插法public void addFirst(int date);//尾插法public void addLast(int date);//任意位置插入,第一个节点为0号下标public void addIndex(int index, int date);//删除第一次出现值为key的节点public void remove(int key);//判断链表中是否存在值为key的节点public boolean contains(int key);//删除所有值为key的节点public void removeAllKey(int key);//获得链表的长度public int size();//清空链表public void clear();//显示链表public void disPlay();
}
先创建一个链表类实现Ilist接口
public class MySingleList implements Ilist{//内部类static class ListNode{public int val;public ListNode next;public ListNode(int val) {this.val = val;}}//链表的头public ListNode head;//创建链表public void creatList(){ListNode node1 = new ListNode(5);ListNode node2 = new ListNode(6);ListNode node3 = new ListNode(8);ListNode node4 = new ListNode(10);ListNode node5 = new ListNode(15);node1.next = node2;node2.next = node3;node3.next = node4;node4.next = node5;this.head = node1;}@Overridepublic void addFirst(int date) {}@Overridepublic void addLast(int date) {}@Overridepublic void addIndex(int index, int date) {}@Overridepublic void remove(int key) {}@Overridepublic boolean contains(int key) {return false;}@Overridepublic void removeAllKey(int key) {}@Overridepublic int size() {return 0;}@Overridepublic void clear() {}@Overridepublic void disPlay() {}}
接下来对重写的方法由简单到复杂一一实现
完成disPlay方法
@Overridepublic void disPlay() {ListNode cur = head;while(cur != null){System.out.print(cur.val + " ");cur = cur.next;}
为了防止调用完一次函数head的指向会发生变化,所以要对head临时拷贝一份
完成size方法
@Override public int size() {int len = 0;ListNode cur = head;while(cur != null){len++;cur = cur.next;}return len; }
下面是cur的指向轨迹
实现addFirst方法
@Overridepublic void addFirst(int date) {//创建出新的节点ListNode node = new ListNode(date);node.next = head;head = node;
}
测试一下
public class Test {public static void main(String[] args) {MySingleList mySingleList = new MySingleList();mySingleList.creatList();int ret = mySingleList.size();System.out.println(ret);mySingleList.disPlay();System.out.println();mySingleList.addFirst(8);mySingleList.disPlay();System.out.println();}
}
addLast也是同理
@Overridepublic void addLast(int date) {ListNode node = new ListNode(date);ListNode cur = head;while(cur.next != null){cur = cur.next;}cur.next = node;}
测试一下
public class Test {public static void main(String[] args) {MySingleList mySingleList = new MySingleList();mySingleList.creatList();int ret = mySingleList.size();System.out.println(ret);mySingleList.disPlay();System.out.println();mySingleList.addFirst(8);mySingleList.disPlay();System.out.println();mySingleList.addLast(20);mySingleList.disPlay();System.out.println();
}
}
实现addIndex方法
@Overridepublic void addIndex(int index, int date) {int len = size();if(index < 0 || index > len){System.out.println("index位置不合法");return;}if(index == 0){addFirst(date);}if (index == len){addLast(date);}ListNode cur = head;while( index - 1 != 0 ){cur = cur.next;index--;}ListNode node = new ListNode(date);node.next = cur.next;cur.next = node;}
因为是单向链表,cur要指向index下标的前一个位置的节点,对index前面那个节点的next修改,进行插入
测试一下
public class Test {public static void main(String[] args) {MySingleList mySingleList = new MySingleList();mySingleList.creatList();int ret = mySingleList.size();System.out.println(ret);mySingleList.disPlay();System.out.println();mySingleList.addFirst(8);mySingleList.disPlay();System.out.println();mySingleList.addLast(20);mySingleList.disPlay();System.out.println();mySingleList.addIndex(2,66);mySingleList.disPlay();System.out.println();
}
}
实现contains方法
@Overridepublic boolean contains(int key) {ListNode cur = head;while(cur != null){if(cur.val == key){return true;}cur = cur.next;}return false;}
这个很好理解
测试↓
public class Test {public static void main(String[] args) {MySingleList mySingleList = new MySingleList();mySingleList.creatList();int ret = mySingleList.size();System.out.println(ret);mySingleList.disPlay();System.out.println();mySingleList.addFirst(8);mySingleList.disPlay();System.out.println();mySingleList.addLast(20);mySingleList.disPlay();System.out.println();mySingleList.addIndex(2,66);mySingleList.disPlay();System.out.println();boolean ret2 = mySingleList.contains(66);System.out.println(ret2);
}
}
实现remove方法
@Overridepublic void remove(int key) {if(head == null){return;}if(head.val == key){head = head.next;return;}ListNode cur = findNodeIndex(key);if(cur != null){cur.next = cur.next.next;}else{System.out.println("没有要删除的key值");return;}}//供remove使用的方法private ListNode findNodeIndex(int key){ListNode cur = head;while(cur.next != null){if(cur.next.val == key){return cur;}cur = cur.next;}return null;}
测试
public class Test {public static void main(String[] args) {MySingleList mySingleList = new MySingleList();mySingleList.creatList();int ret = mySingleList.size();System.out.println(ret);mySingleList.disPlay();System.out.println();mySingleList.addFirst(8);mySingleList.disPlay();System.out.println();mySingleList.addLast(20);mySingleList.disPlay();System.out.println();mySingleList.addIndex(2,66);mySingleList.disPlay();System.out.println();boolean ret2 = mySingleList.contains(66);System.out.println(ret2);mySingleList.remove(66);mySingleList.disPlay();System.out.println();
}
}
实现removeAllKey方法
@Overridepublic void removeAllKey(int key) {if(head == null){return;}ListNode prev = head;ListNode cur = head.next;while(cur != null){if(cur.val == key){prev.next = cur.next;cur = cur.next;}else{prev = cur;cur = cur.next;}}if(head.val == key){head = head.next;}}
测试一下
public class Test {public static void main(String[] args) {MySingleList mySingleList = new MySingleList();mySingleList.creatList();int ret = mySingleList.size();System.out.println(ret);mySingleList.disPlay();System.out.println();mySingleList.addFirst(8);mySingleList.disPlay();System.out.println();mySingleList.addLast(20);mySingleList.disPlay();System.out.println();mySingleList.addIndex(2,66);mySingleList.disPlay();System.out.println();boolean ret2 = mySingleList.contains(66);System.out.println(ret2);mySingleList.remove(66);mySingleList.disPlay();System.out.println();mySingleList.addFirst(9);mySingleList.addIndex(1,9);mySingleList.addIndex(2,9);mySingleList.addIndex(5,9);mySingleList.disPlay();System.out.println();mySingleList.removeAllKey(9);//removeALLKeymySingleList.disPlay();System.out.println();
}
}
只看后两行,把9都删除了
实现clear方法
@Overridepublic void clear() {head = null;}
这种方法简单,但是会造成内存泄漏,需要将节点的每一个next值都置为null ,需要下面这种方法
@Overridepublic void clear() {ListNode cur = head;while(cur != null){ListNode curN = cur.next;cur.next = null;cur = curN;}head = null;}
这种类似于交换两个变量的数值,需要临时拷贝一份
下面是测试类的全部代码
public class Test {public static void main(String[] args) {MySingleList mySingleList = new MySingleList();mySingleList.creatList();int ret = mySingleList.size();System.out.println(ret);mySingleList.disPlay();System.out.println();mySingleList.addFirst(8);mySingleList.disPlay();System.out.println();mySingleList.addLast(20);mySingleList.disPlay();System.out.println();mySingleList.addIndex(2,66);mySingleList.disPlay();System.out.println();boolean ret2 = mySingleList.contains(66);System.out.println(ret2);mySingleList.remove(66);mySingleList.disPlay();System.out.println();mySingleList.addFirst(9);mySingleList.addIndex(1,9);mySingleList.addIndex(2,9);mySingleList.addIndex(5,9);mySingleList.disPlay();System.out.println();mySingleList.removeAllKey(9);//removeALLKeymySingleList.disPlay();System.out.println();mySingleList.clear();mySingleList.disPlay();System.out.println();mySingleList.addFirst(1);mySingleList.disPlay();}
}
下面是MySingleList类的全部代码
public class MySingleList implements Ilist{static class ListNode{public int val;public ListNode next;public ListNode(int val) {this.val = val;}}public ListNode head;public void creatList(){ListNode node1 = new ListNode(5);ListNode node2 = new ListNode(6);ListNode node3 = new ListNode(8);ListNode node4 = new ListNode(10);ListNode node5 = new ListNode(15);node1.next = node2;node2.next = node3;node3.next = node4;node4.next = node5;this.head = node1;}@Overridepublic void addFirst(int date) {ListNode node = new ListNode(date);node.next = head;head = node;}@Overridepublic void addLast(int date) {ListNode node = new ListNode(date);ListNode cur = head;while(cur.next != null){cur = cur.next;}cur.next = node;}@Overridepublic void addIndex(int index, int date) {int len = size();if(index < 0 || index > len){System.out.println("index位置不合法");return;}if(index == 0){addFirst(date);}if (index == len){addLast(date);}ListNode cur = head;while( index - 1 != 0 ){cur = cur.next;index--;}ListNode node = new ListNode(date);node.next = cur.next;cur.next = node;}@Overridepublic boolean contains(int key) {ListNode cur = head;while(cur != null){if(cur.val == key){return true;}cur = cur.next;}return false;}@Overridepublic void remove(int key) {if(head == null){return;}if(head.val == key){head = head.next;return;}ListNode cur = findNodeIndex(key);if(cur != null){cur.next = cur.next.next;}else{System.out.println("没有要删除的key值");return;}}//供remove使用的方法private ListNode findNodeIndex(int key){ListNode cur = head;while(cur.next != null){if(cur.next.val == key){return cur;}cur = cur.next;}return null;}@Overridepublic void removeAllKey(int key) {if(head == null){return;}ListNode prev = head;ListNode cur = head.next;while(cur != null){if(cur.val == key){prev.next = cur.next;cur = cur.next;}else{prev = cur;cur = cur.next;}}if(head.val == key){head = head.next;}}@Overridepublic int size() {int len = 0;ListNode cur = head;while(cur != null){len++;cur = cur.next;}return len;}@Overridepublic void clear() {ListNode cur = head;while(cur != null){ListNode curN = cur.next;cur.next = null;cur = curN;}head = null;}@Overridepublic void disPlay() {ListNode cur = head;while(cur != null){System.out.print(cur.val + " ");cur = cur.next;}}}
IList接口中的全部代码
public interface Ilist {//头插法public void addFirst(int date);//尾插法public void addLast(int date);//任意位置插入,第一个节点为0号下标public void addIndex(int index, int date);//删除第一次出现值为key的节点public void remove(int key);//判断链表中是否存在值为key的节点public boolean contains(int key);//删除所有值为key的节点public void removeAllKey(int key);//获得链表的长度public int size();//清空链表public void clear();//显示链表public void disPlay();
}