1.概述
在计算机科学中,链表是数据元素的线性集合,其每个元素都指向下一个元素,元素存储上并不连续
分类
-
单向链表,每个元素只知道其下一个元素是谁
-
双向链表,每个元素知道其上一个元素和下一个元素
-
循环链表,通常的链表尾节点 tail 指向的都是 null,而循环链表的 tail 指向的是头节点 head
链表内还有一种特殊的节点称为哨兵(Sentinel)节点,也叫做哑元( Dummy)节点,它不存储数据,通常用作头尾,用来简化边界判断,如下图所示
随机访问性能
根据 index 查找,时间复杂度 O ( n ) O(n) O(n)
插入或删除性能
- 起始位置: O ( 1 ) O(1) O(1)
- 结束位置:如果已知 tail 尾节点是 O ( 1 ) O(1) O(1),不知道 tail 尾节点是 O ( n ) O(n) O(n)
- 中间位置:根据 index 查找时间 + O ( 1 ) O(1) O(1)
2.单向链表
public class SinglyLinkedList implements Iterable<Integer> {//定义头节点private Node head = null;/*** 在头部添加** @param value*/public void addFirst(int value) {head = new Node(head, value);}/*** 在尾部添加** @param value*/public void addLast(int value) {if (head == null) {addFirst(value);} else {Node last = findLast();last.next = new Node(null, value);}}/*** 根据索引插入** @param index* @param value*/public void insert(int index, int value) {if (index < 0) {throw new IndexOutOfBoundsException("index:" + index + " error");}if (index == 0) {addFirst(value);return;}Node prev = findNode(index - 1);if (prev == null) {throw new IndexOutOfBoundsException("index:" + index + " error");}prev.next = new Node(prev.next, value);}/*** 删除第一个节点*/public void removeFirst() {if (head == null) {throw new IndexOutOfBoundsException("数组为空,不能删除");}head = head.next;}/*** 根据索引删除节点** @param index*/public void remove(int index) {if (index < 0) {throw new IndexOutOfBoundsException("index:" + index + " error");}if (index == 0) {removeFirst();return;}Node prev = findNode(index - 1);if (prev == null) {throw new IndexOutOfBoundsException("index:" + index + " error");}Node removed = prev.next;if (removed == null) {throw new IndexOutOfBoundsException("index:" + index + " error");}prev.next = removed.next;}/*** 根据索引获取节点的值** @param index* @return*/public int get(int index) {Node node = findNode(index);if (node == null) {throw new IndexOutOfBoundsException("index:" + index + " error");}return node.value;}private Node findNode(int index) {/*int i = 0;for (Node pointer = head; pointer != null; pointer = pointer.next, i++) {if(i == index){return pointer;}}return null;*/int i = 0;Node pointer = head;while (pointer != null) {if (i == index) {return pointer;}pointer = pointer.next;i++;}return null;}/*** 查找最后一个节点** @return*/private Node findLast() {Node pointer = head;while (pointer != null && pointer.next != null) {pointer = pointer.next;}return pointer;}/*** 循环操作** @param consumer*/public void foreach(Consumer<Integer> consumer) {/*Node pointer = head;while (pointer != null) {consumer.accept(pointer.value);pointer = pointer.next;}*/for (Node pointer = head; pointer != null; pointer = pointer.next) {consumer.accept(pointer.value);}}/*** 递归循环*/public void recursion(Consumer<Integer> consumer) {recursion(head, consumer);}private void recursion(Node node, Consumer<Integer> consumer) {if (node != null) {consumer.accept(node.value);recursion(node.next, consumer);}}/*** 迭代器** @return*/@Overridepublic Iterator<Integer> iterator() {return new Iterator<Integer>() {Node pointer = head;@Overridepublic boolean hasNext() {return pointer != null;}@Overridepublic Integer next() {int value = pointer.value;pointer = pointer.next;return value;}};}/*** 定义节点信息*/private static class Node {private Node next;//下一个节点的指针private int value;//值public Node(Node next, int value) {this.next = next;this.value = value;}}
}
3.单向链表-带哨兵
public class SinglyLinkedListSentinel implements Iterable<Integer> {//定义哨兵节点private Node sentinel = new Node(null, -1);/*** 在头部添加** @param value*/public void addFirst(int value) {insert(0, value);}/*** 在尾部添加** @param value*/public void addLast(int value) {Node last = findLast();last.next = new Node(null, value);}/*** 根据索引插入** @param index* @param value*/public void insert(int index, int value) {if (index < 0) {throw new IndexOutOfBoundsException("index:" + index + " error");}Node prev = findNode(index - 1);if (prev == null) {throw new IndexOutOfBoundsException("index:" + index + " error");}prev.next = new Node(prev.next, value);}/*** 删除第一个节点*/public void removeFirst() {remove(0);}/*** 根据索引删除节点** @param index*/public void remove(int index) {if (index < 0) {throw new IndexOutOfBoundsException("index:" + index + " error");}Node prev = findNode(index - 1);if (prev == null) {throw new IndexOutOfBoundsException("index:" + index + " error");}Node removed = prev.next;if (removed == null) {throw new IndexOutOfBoundsException("index:" + index + " error");}prev.next = removed.next;}/*** 根据索引获取节点的值** @param index* @return*/public int get(int index) {Node node = findNode(index);if (node == null) {throw new IndexOutOfBoundsException("index:" + index + " error");}return node.value;}private Node findNode(int index) {/*int i = 0;for (Node pointer = head; pointer != null; pointer = pointer.next, i++) {if(i == index){return pointer;}}return null;*/int i = -1;Node pointer = sentinel;while (pointer != null) {if (i == index) {return pointer;}pointer = pointer.next;i++;}return null;}/*** 查找最后一个节点** @return*/private Node findLast() {Node pointer = sentinel;while (pointer.next != null) {pointer = pointer.next;}return pointer;}/*** 循环操作** @param consumer*/public void foreach(Consumer<Integer> consumer) {/*Node pointer = head;while (pointer != null) {consumer.accept(pointer.value);pointer = pointer.next;}*/for (Node pointer = sentinel.next; pointer != null; pointer = pointer.next) {consumer.accept(pointer.value);}}/*** 递归循环*/public void recursion(Consumer<Integer> consumer) {recursion(sentinel.next, consumer);}private void recursion(Node node, Consumer<Integer> consumer) {if (node != null) {consumer.accept(node.value);recursion(node.next, consumer);}}/*** 迭代器** @return*/@Overridepublic Iterator<Integer> iterator() {return new Iterator<Integer>() {Node pointer = sentinel.next;@Overridepublic boolean hasNext() {return pointer != null;}@Overridepublic Integer next() {int value = pointer.value;pointer = pointer.next;return value;}};}/*** 定义节点信息*/private static class Node {private Node next;//下一个节点的指针private int value;//值public Node(Node next, int value) {this.next = next;this.value = value;}}
}
4.双向链表-带哨兵
public class DoublyLinkedListSentinel implements Iterable<Integer> {private Node head = new Node(null, -1, null);//头哨兵节点private Node tail = new Node(null, -2, null);//尾哨兵节点public DoublyLinkedListSentinel() {this.head.next = tail;//头哨兵的下一个节点指向尾节点this.tail.prev = head;//尾哨兵的上一个节点指向头节点}/*** 查询节点** @param index* @return*/private Node findNode(int index) {if (index < -1) {throw new IndexOutOfBoundsException("index:" + index + " error");}int i = -1;Node pointer = head;while (pointer != tail) {if (index == i) {return pointer;}pointer = pointer.next;i++;}return null;}/*** 根据索引插入节点** @param index* @param value*/public void insert(int index, int value) {Node prev = findNode(index - 1);//上一个节点if (prev == null) {throw new IndexOutOfBoundsException("index:" + index + " error");}Node next = prev.next;Node add = new Node(prev, value, next);prev.next = add;next.prev = add;}/*** 根据索引删除** @param index*/public void remove(int index) {Node prev = findNode(index - 1);//上一个节点if (prev == null) {throw new IndexOutOfBoundsException("index:" + index + " error");}Node removed = prev.next;if (removed == tail) {throw new IndexOutOfBoundsException("index:" + index + " error");}Node next = removed.next;prev.next = next;next.prev = prev;}/*** 在头部添加** @param value*/public void addFirst(int value) {insert(0, value);}/*** 移除第一个节点*/public void removeFirst() {remove(0);}/*** 在尾部追加** @param value*/public void addLast(int value) {Node prev = tail.prev;Node add = new Node(prev, value, tail);prev.next = add;tail.prev = add;}/*** 移除最后一个节点*/public void removeLast() {Node removed = tail.prev;//要移除的节点if (tail.prev == head) {throw new IndexOutOfBoundsException("暂无最后一个节点");}Node prev = removed.prev;//上一个节点tail.prev = prev;prev.next = tail;}/*** 迭代** @return*/@Overridepublic Iterator<Integer> iterator() {return new Iterator<>() {Node pointer = head.next;@Overridepublic boolean hasNext() {return pointer != tail;}@Overridepublic Integer next() {int value = pointer.value;pointer = pointer.next;return value;}};}/*** 定义节点信息*/private static class Node {private Node prev;//上一个节点的指针private int value;//值private Node next;//下一个节点的指针public Node(Node prev, int value, Node next) {this.prev = prev;this.value = value;this.next = next;}}
}
5.双向环形链表-带哨兵
双向环形链表带哨兵,这时哨兵既作为头,也作为尾
public class DoublyCircularLinkedListSentinel implements Iterable<Integer> {private Node sentinel = new Node(null, -1, null);//定义哨兵节点public DoublyCircularLinkedListSentinel() {this.sentinel.prev = sentinel;this.sentinel.next = sentinel;}/*** 添加头部节点** @param value*/public void addFirst(int value) {Node prev = sentinel;Node next = sentinel.next;Node add = new Node(prev, value, next);prev.next = add;next.prev = add;}/*** 添加尾部节点** @param value*/public void addLast(int value) {Node next = sentinel;Node prev = sentinel.prev;Node add = new Node(prev, value, next);prev.next = add;next.prev = add;}/*** 移除头部节点*/public void removeFirst() {Node prev = sentinel;Node removed = sentinel.next;if (removed == sentinel) {throw new IndexOutOfBoundsException("暂无节点");}Node next = removed.next;prev.next = next;next.prev = prev;}/*** 移除头部节点*/public void removeLast() {Node next = sentinel;Node removed = sentinel.prev;if (removed == sentinel) {throw new IndexOutOfBoundsException("暂无节点");}Node prev = removed.prev;prev.next = next;next.prev = prev;}/*** 根据值删除节点** @param value*/public void removeByValue(int value) {Node removed = findByValue(value);if (removed == null) {return;}Node prev = removed.prev;Node next = removed.next;prev.next = next;next.prev = prev;}/*** 根据值查找节点** @param value* @return*/private Node findByValue(int value) {Node pointer = sentinel.next;while (pointer != sentinel) {if (pointer.value == value) {return pointer;}pointer = pointer.next;}return null;}/*** 递归遍历** @param consumer*/public void recursion(Consumer<Integer> consumer) {recursion(sentinel.next, consumer);}/*** 递归遍历** @param node* @param consumer*/private void recursion(Node node, Consumer<Integer> consumer) {if (node != sentinel) {consumer.accept(node.value);recursion(node.next, consumer);}}//节点类private static class Node {private Node prev;private int value;private Node next;public Node(Node prev, int value, Node next) {this.prev = prev;this.value = value;this.next = next;}}@Overridepublic Iterator<Integer> iterator() {return new Iterator<Integer>() {Node pointer = sentinel.next;@Overridepublic boolean hasNext() {return pointer != sentinel;}@Overridepublic Integer next() {int value = pointer.value;pointer = pointer.next;return value;}};}
}