1、继续学习单链表,终于摆脱数组的魔爪了,单链表分为数据域(前突)和引用域(指针域)(后继),还有一个头结点(就好比一辆火车,我们只关心火车头,不关心其它车厢,只需知晓车头顺藤摸瓜即可),头结点没有前突,尾结点没有后继,注意不是前仆后继。
1 public class Node {//包装车厢 2 /** 3 * 人无完人,如有bug,还请斧正 4 */ 5 public long data;// 数据域 6 public Node next;// 指针域,后指针
public Node previous;// 指针域,前指针 7 8 public Node(long value) {// 构造函数 9 this.data = value; 10 } 11 12 public void display() { 13 System.out.print(data + " "); 14 } 15 }
1 //单链表,头结点插入 2 public class LinkList { 3 private Node first;// 火车头,保存头结点的一个指向 4 5 public LinkList() {// 初始化 6 first = null; 7 } 8 9 public static void main(String[] args) { 10 LinkList ll = new LinkList(); 11 ll.insert(4);// 添加 12 ll.insert(57); 13 ll.insert(32); 14 ll.insert(68); 15 16 ll.display();// 先进后出 17 18 ll.delete(32);// 删除32 19 System.out.println(""); 20 System.out.println("--------"); 21 ll.display(); 22 23 System.out.println(""); 24 System.out.println("--------"); 25 26 ll.deleteFirst();// 删除头结点 27 ll.display(); 28 29 System.out.println(""); 30 System.out.println("--------"); 31 Node node = ll.find(4);// 查找4 32 node.display(); 33 } 34 35 public Node deleteFirst() {// 删除头结点 36 first = first.next;// 头结点为头结点的下一个 37 return first; 38 } 39 40 public Node find(long value) {// 按值查找,返回null或索引值 41 Node current = first;// 从头结点开始 42 43 while (current.data != value) { 44 45 if (current.next == null) {// 尾结点后继为null 46 return null; 47 } 48 current = current.next; 49 } 50 return current;// 找到返回 51 } 52 53 public Node delete(long value) {// 删除任意结点 54 Node current = first; 55 Node previous = first; 56 57 while (current.data != value) { 58 if (current.next == null) {// 没有找到 59 return null; 60 } 61 previous = current;// 保存邻近的两个结点 62 current = current.next; 63 } 64 65 if (current == first) {// 第一个结点 66 first = first.next; 67 } else {// 后面的结点 68 previous.next = current.next;// 上一个结点的下一个变为当前结点的下一个,当前结点删除 69 } 70 return current;// 结点类,返回结点类型 71 } 72 73 public void insert(long value) {// 在头结点之后插入 74 Node node = new Node(value);// 创建新的结点 75 // 这里深深体会一下精妙之处,first保存着一个指向 76 node.next = first;// 图示第一步 77 first = node;// 图示第二步 78 } 79 80 public void display() {// 显示 81 Node current = first; 82 while (current != null) { 83 current.display(); 84 current = current.next; 85 } 86 } 87 }
单链表时只能实现头部依次插入数据,为了弥补这个局限性,所以我们得学习双端链表,即链表中保存着对最后一个链结点引用的链表。
2、双端链表
1 //双端链表,头尾结点都可以插入 2 public class FirstLastLinkList { 3 private Node first;// 火车头,保存头结点的一个指向第一个node 4 private Node last;// 火车尾,保存头结点的一个指向最后一个node 5 6 public FirstLastLinkList() { 7 first = null; 8 } 9 10 public static void main(String[] args) { 11 FirstLastLinkList fll = new FirstLastLinkList(); 12 13 fll.insertLast(26); 14 fll.insertLast(24); 15 fll.insertLast(65); 16 fll.insertLast(17); 17 fll.display();// 先进先出 18 19 System.out.println(""); 20 System.out.println("--------"); 21 22 fll.deleteFirst(); 23 fll.display(); 24 25 System.out.println(""); 26 System.out.println("--------"); 27 } 28 29 public Node deleteFirst() {// 删除头结点 30 if (first.next == null) { 31 last = null;// 没有结点 32 } 33 first = first.next; 34 return first; 35 } 36 37 public Node find(long value) {// 查找 38 Node current = first; 39 40 while (current.data != value) { 41 42 if (current.next == null) { 43 return null; 44 } 45 current = current.next; 46 } 47 return current; 48 } 49 50 public Node delete(long value) {// 删除任意结点 51 Node current = first; 52 Node previous = first; 53 54 while (current.data != value) { 55 if (current.next == null) {// 没有找到 56 return null; 57 } 58 previous = current; 59 current = current.next; 60 } 61 62 if (current == first) {// 第一个结点 63 first = first.next; 64 } else {// 后面的结点 65 previous.next = current.next; 66 } 67 return current; 68 } 69 70 public void insert(long value) {// 在头结点插入 71 Node node = new Node(value);// 创建新的结点 72 if (isEmpty()) { 73 last = node; 74 } 75 node.next = first; 76 first = node; 77 } 78 79 public void insertLast(long value) {// 在尾结点插入 80 Node node = new Node(value); 81 if (isEmpty()) {// 为空 82 first = node; 83 } else {// 不为空 84 last.next = node;// 图示1 85 } 86 last = node;// 图示2 87 } 88 89 public boolean isEmpty() {// 是否空 90 return first == null; 91 } 92 93 public void display() {// 显示 94 Node current = first; 95 while (current != null) { 96 current.display(); 97 current = current.next; 98 } 99 } 100 }
3、双向链表,Node就会多一个属性previous,每个结点除了保存对下一个结点的引用,同时还保存着对前一个结点的引用。
1 //双向链表,头尾结点都可以插入和删除 2 public class DoubleLinkList { 3 private Node first;// 火车头 4 private Node last;// 火车尾 5 6 public DoubleLinkList() { 7 first = null; 8 } 9 10 public static void main(String[] args) { 11 DoubleLinkList dll = new DoubleLinkList(); 12 dll.insertLast(342); 13 dll.insertLast(54); 14 dll.insertLast(24); 15 dll.display(); 16 17 System.out.println(""); 18 System.out.println("--------"); 19 20 while (!dll.isEmpty()) { 21 dll.deleteFirst(); 22 dll.display(); 23 System.out.println(""); 24 System.out.println("--------"); 25 } 26 27 System.out.println(""); 28 System.out.println("--------"); 29 30 System.out.println(""); 31 System.out.println("--------"); 32 } 33 34 public Node deleteFirst() {// 从头结点开始删除 35 if (first.next == null) {// 判断头结点是否有下一个结点 36 last = null;// 没有结点 37 } else { 38 first.next.previous = null;// 设置头结点的下一个结点的previous为null 39 } 40 first = first.next; 41 return first; 42 } 43 44 public Node deleteLast() {// 从尾结点开始删除 45 if (first.next == null) {// 头结点后面没有其它结点,当前为最后一个结点 46 first = null; 47 } else { 48 last.previous.next = null;// 设置尾结点的前一个结点的next为null 49 } 50 last = last.previous; 51 return last; 52 } 53 54 public Node find(long value) {// 查找 55 Node current = first; 56 57 while (current.data != value) { 58 59 if (current.next == null) { 60 return null; 61 } 62 current = current.next; 63 } 64 return current; 65 } 66 67 public Node delete(long value) {// 删除任意结点 68 Node current = first; 69 // 不需要临时的指针域 70 while (current.data != value) { 71 if (current.next == null) {// 没有找到 72 return null; 73 } 74 current = current.next; 75 } 76 if (current == first) {// 第一个结点 77 first = first.next; 78 } else {// 后面的结点 79 current.previous.next = current.next; 80 } 81 return current; 82 } 83 84 public void insert(long value) {// 在头结点之后插入 85 Node node = new Node(value);// 创建新的结点 86 if (isEmpty()) {// 要对链表进行判断,为空则设置尾结点为新添加的结点 87 last = node; 88 } else { 89 first.previous = node;// 不为空,需要设置头结点前一个结点为新添加的结点 90 } 91 node.next = first; 92 first = node; 93 } 94 95 public void insertLast(long value) {// 在尾结点之后插入 96 Node node = new Node(value);// 创建新的结点 97 if (isEmpty()) {// 为空,直接设置头结点为新添加的结点 98 first = node; 99 } else { 100 last.next = node;// 设置尾结点的后一个结点为新添加的结点, 101 } 102 node.previous = last;// 新添加的前一个结点为新添加的结点 103 last = node; 104 } 105 106 public boolean isEmpty() {// 是否空 107 return first == null; 108 } 109 110 public void display() {// 显示 111 Node current = first; 112 while (current != null) { 113 current.display(); 114 current = current.next; 115 } 116 } 117 }
删除后JVM自动回收垃圾