链表(Linked List)是一种线性数据结构,由一系列节点(Node)组成。每个节点包含两部分:元素值(Element Value)和指向下一个节点的指针(Pointer)。链表可以分为多种类型,如单向链表、双向链表、循环链表等。元素在存储上并不连续。
(1)单向链表:每个元素只知道下一个元素。
(2)双向链表:每个元素知道下一个元素和上一个元素。
(3)循环链表:通常的链表为节点tail指向null,但是循环链表的tail指向head。
链表内还有一种特殊的节点,成为哨兵(Sentinel)节点,也叫做哑元(Dummy)节点,他并不存储数据,用来减缓别介判断。
随机访问:
根据index查找,时间复杂度O(n)。
插入或者删除:
起始位置:O(1)。
结束位置:如果已知tail为节点是O(1),否则为O(n)。
中间位置:根据index查找时间+O(1)。
package org.alogorithm.linkedList; import java.util.Iterator; import java.util.function.Consumer; public class SingLinkListMain { public static void main(String[] args) { SingLinkList singLinkList = new SingLinkList(); singLinkList.addFirst(1); singLinkList.addFirst(2); singLinkList.addFirst(3); singLinkList.addFirst(4); singLinkList.addFirst(5); //使用Consumer+while实现 singLinkList.consumerLoop1(value -> System.out.println(value + "while,")); System.out.println("----------------------------------------"); singLinkList.addLast(99);//尾部添加一个元素 singLinkList.addLast(100);//尾部添加一个元素 //使用Consumer+for实现 singLinkList.consumerLoop2(value -> System.out.println(value + "for")); System.out.println("----------------------------------------"); int res = singLinkList.get(3); System.out.println("查询结果为" + res); singLinkList.insert(0, 111); singLinkList.insert(3, 111); //使用迭代器实现 for (Integer integer : singLinkList) { System.out.println(integer + "iterable"); } System.out.println("----------------------------------------"); /*int reserr = singLinkList.get(100); System.out.println("查询结果为"+reserr);*/ // singLinkList.removeFirst();//删除第一个节点 singLinkList.reomve(0); singLinkList.reomve(3); singLinkList.reomve(99); //使用递归 singLinkList.recursionLoop(e -> { System.out.println(e + "recursion"); }, singLinkList.head); // System.out.println(singLinkList.findLast()); } } //单向链表 class SingLinkList implements Iterable
{ // head指针 Node head; //删除指定索引节点 public void reomve(int index) { if (index < 0) { IndexOutOfBoundsException(head, "索引不能为负"); } else if (index == 0) { removeFirst(); } Node node = findNode(index);//当前个节点 IndexOutOfBoundsException(node, "当前节点为空"); Node beforNode = findNode(index - 1);//上一个节点 beforNode.next = node.next; } //删除第一个节点 public void removeFirst() { IndexOutOfBoundsException(head, "链表为空无"); head = head.next;//将head设置为之前的head.next第二个节点 } //向索引位置添加一个元素 public void insert(int index, int value) { Node afterNode = findNode(index);//后一个节点 //构建新的节点 Node newNode = new Node(value, afterNode); if (index == 0) { //索引为0向头部添加 addFirst(value); } else { Node beforNode = findNode(index - 1); //否则将befor的next属性设置为当前节点 IndexOutOfBoundsException(beforNode, "索引位置异常"); beforNode.next = newNode; } } //抛出异常 private static void IndexOutOfBoundsException(Node beforNode, String msg) { if (beforNode == null) { throw new IndexOutOfBoundsException(msg); } } //获取节点的值 public int get(int index) { Node node = findNode(index); IndexOutOfBoundsException(node, "索引位置异常"); return node.value; } //获取索引的元素 private Node findNode(int index) { Node point = head; int i = 0; while (point != null) { if (i == index) { return point; } else { point = point.next; i++; } } return null; } //向最后添加一个元素 public void addLast(int value) { Node last = findLast();//找到最后一个节点 if (last == null) { //没有最后一个就添加第一个 addFirst(value); } else { //否则设置最有一个节点的next属性为新的Node last.next = new Node(value, null); } } //查找最后一个元素 public Node findLast() { Node point = head; if (head == null) { return null; } while (true) { if (point.next != null) { point = point.next; } else { return point; } } } //头部添加一个元素 public void addFirst(int value) { //链表为空 // head = new Node(value,null); //链表非空 head = new Node(value, head);//链表为空时head就是null } public void recursionLoop(Consumer consumer, Node point) { if (point != null) { consumer.accept(point.value); // 先输出当前节点的值 recursionLoop(consumer, point.next); // 再递归处理下一个节点 } } //迭代器遍历 @Override public Iterator iterator() { return new Iterator () { Node point = head; @Override public boolean hasNext() { return point != null; } @Override public Integer next() { int value = point.value; point = point.next; return value; } }; } //循环遍历 for public void consumerLoop2(Consumer consumer) { for (Node point = head; point != null; point = point.next) { consumer.accept(point.value); } } //循环遍历 while public void consumerLoop1(Consumer consumer) { Node point = head; while (point != null) { consumer.accept(point.value); point = point.next; } } //节点 private static class Node { int value;//值 Node next;//下一个节点 public Node(int value, Node next) { this.value = value; this.next = next; } } } 这是一个普通单向链表的全部功能实现,但是实现起来比较麻烦。
补充:关于类需不需要带static:
(1)Node内部类可以添加static关键字,这是因为Java允许在类中定义静态成员。将内部类声明为静态的,意味着它不再依赖于外部类的实例。
(2)静态内部类不能访问外部类的非静态成员(包括字段和方法)。
(3)由于不依赖外部类实例,创建静态内部类的对象不需要外部类对象。
加入哨兵之后,就不存在head为空的情况,也不存在链表为空,某个节点上一个元素为空,插入头部时链表为空的情况,但是对应的循环遍历要从head.next开始,可以简化很多代码。
package org.alogorithm.linkedList; import java.util.Iterator; import java.util.function.Consumer; public class SingLinkSentryListMain { public static void main(String[] args) { SingLinkSentryList singLinkSentryList = new SingLinkSentryList(); singLinkSentryList.addLast(69); singLinkSentryList.addLast(70); //使用Consumer+while实现 singLinkSentryList.consumerLoop1(value -> System.out.println(value + "while,")); System.out.println(singLinkSentryList.get(0)); //System.out.println(singLinkSentryList.get(99)); singLinkSentryList.insert(0,99); // singLinkSentryList.insert(99,99); System.out.println("----------------------------------------"); //使用Consumer+for实现 singLinkSentryList.consumerLoop2(value -> System.out.println(value + "for")); System.out.println("----------------------------------------"); singLinkSentryList.reomve(1); singLinkSentryList.reomve(0); // singLinkSentryList.reomve(99); //使用迭代器实现 for (Integer integer : singLinkSentryList) { System.out.println(integer + "iterable"); } System.out.println("----------------------------------------"); //使用递归 /* singLinkSentryList.recursionLoop(e -> { System.out.println(e + "recursion"); }, singLinkSentryList.head);*/ } } //单向链表 class SingLinkSentryList implements Iterable
{ // head指针 Node head=new Node(1,null);//头指针指向哨兵 //删除指定索引节点 public void reomve(int index) { if (index < 0) { IndexOutOfBoundsException(head, "索引不能为负"); } Node node = findNode(index);//当前个节点 IndexOutOfBoundsException(node, "当前节点为空"); Node beforNode = findNode(index - 1);//上一个节点 beforNode.next = node.next; } //删除第一个节点 public void removeFirst() { IndexOutOfBoundsException(head, "链表为空无"); reomve(0); } //向索引位置添加一个元素 public void insert(int index, int value) { Node afterNode = findNode(index);//后一个节点 //构建新的节点 Node newNode = new Node(value, afterNode); Node beforNode = findNode(index - 1); //否则将befor的next属性设置为当前节点 IndexOutOfBoundsException(beforNode, "索引位置异常"); beforNode.next = newNode; } //抛出异常 private static void IndexOutOfBoundsException(Node beforNode, String msg) { if (beforNode == null) { throw new IndexOutOfBoundsException(msg); } } //获取节点的值 public int get(int index) { Node node = findNode(index); IndexOutOfBoundsException(node, "索引位置异常"); return node.value; } //获取索引的元素 private Node findNode(int index) { Node point = head; int i = -1; while (point != null) { if (i == index) { return point; } else { point = point.next; i++; } } return null; } //向最后添加一个元素 public void addLast(int value) { Node last = findLast();//因为有哨兵,head不可能为空 last.next = new Node(value, null); } //查找最后一个元素 public Node findLast() { Node point = head; while (true) { if (point.next != null) { point = point.next; } else { return point; } } } //头部添加一个元素 public void addFirst(int value) { insert(0,value); } public void recursionLoop(Consumer consumer, Node point) { if (point != null) { consumer.accept(point.value); // 先输出当前节点的值 recursionLoop(consumer, point.next); // 再递归处理下一个节点 } } //迭代器遍历 @Override public Iterator iterator() { return new Iterator () { Node point = head.next; @Override public boolean hasNext() { return point != null; } @Override public Integer next() { int value = point.value; point = point.next; return value; } }; } //循环遍历 for public void consumerLoop2(Consumer consumer) { for (Node point = head.next; point != null; point = point.next) { consumer.accept(point.value); } } //循环遍历 while public void consumerLoop1(Consumer consumer) { Node point = head.next; while (point != null) { consumer.accept(point.value); point = point.next; } } //节点 private static class Node { int value;//值 Node next;//下一个节点 public Node(int value, Node next) { this.value = value; this.next = next; } } }