现虽然顺序表的查询很快,时间复杂度为 O(1) , 但是增删的效率是比较低的,因为每一次增删操作都伴随着大量的数据元素移动。
所以可以使用另外一种存储结构实现线性表,链式存储结构。
链表是一种物理存储单元上非连续、非顺序的存储结构,其物理结构不能只管的表示数据元素的逻辑顺序,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列的结点(链表中的每一个元素称为结点)组成,结点可以在运行时动态生成。



单向链表是链表的一种,它由多个结点组成,每个结点都由一个数据域和一个指针域组成,数据域用来存储数据,指针域用来指向其后继结点。
链表的头结点的数据域不存储数据,指针域指向第一个真正存储数据的结点。

public class LinkList<T> implements Iterable<T> { //记录头节点 private Node head; //记录元素个数 private int n; public class Node { //存储元素 public T item; //指向下一个结点 public Node next; public Node(T item, Node next) { this.item = item; this.next = next; } } //构造函数 public LinkList() { //初始化头节点 this.head = new Node(null, null); //初始化个数 this.n = 0; } //清空链表 public void clear() { this.head = null; this.n = 0; } //获取链表的长度 public int length() { return n; } //判断链表是否为空 public boolean isEmpty() { return n == 0; } //获取指定位置i出的元素 public T get(int i) { Node m = head.next; //通过头结点,循环往后找到第i个元素 for (int j = 0; j < i; j++) { m = m.next; } return m.item; } //向链表中添加元素t public void insert(T t) { //找到当前最后一个结点 Node m = head; while (m.next != null) { m = m.next; } //创建新节点,值为t Node tNode = new Node(t, null); //最后一个元素指向新节点 m.next = tNode; //元素个数+1 n++; } //向指定位置i出,添加元素t public void insert(int i, T t) { //找出i之前的结点 Node pre = this.head; for (int j = 0; j < i; j++) { pre = pre.next; } //指向i结点 Node curr = pre.next; //创建结点,值为t,指向curr Node node = new Node(t, curr); //i之前的结点pre,指向node pre.next = node; //元素数+1 n++; } //删除指定位置i处的元素,并返回被删除的元素 public T remove(int i) { //找到i位置的前一个节点 Node pre = head; for (int index = 0; index <= i - 1; i++) { pre = pre.next; } //要找到i位置的结点 Node curr = pre.next; //找到i位置的下一个结点 Node nNode = curr.next; //前一个结点指向下一个结点 pre.next = nNode; //元素个数-1 n--; return curr.item; } //查找元素t在链表中第一次出现的位置 public int indexOf(T t) { //从头结点开始,依次找到每一个结点,取出item,和t比较,如果相同,就找到了 Node n = head; for (int i = 0; n.next != null; i++) { n = n.next; if (n.item.equals(t)) { return i; } } return -1; } @Override public Iterator<T> iterator() { return new Literator(); } public class Literator implements Iterator{ private Node n; public Literator(){ this.n=head; } @Override public boolean hasNext() { return n.next!=null; } @Override public Object next() { n = n.next; return n.item; } }}public static void main(String[] args) { //创建单向链表对象 LinkList<String> sl = new LinkList<>(); //测试插入 sl.insert("T1"); sl.insert("T2"); sl.insert("T3"); sl.insert(1, "T4"); for (String s : sl) { System.out.println(s); } System.out.println("------------------------------------------"); //测试获取 String getResult = sl.get(1); System.out.println("获取索引1处的结果为:" + getResult); //测试删除 String removeResult = sl.remove(0); System.out.println("删除的元素是:" + removeResult); //测试清空 sl.clear(); System.out.println("清空后的线性表中的元素个数为:" + sl.length());}
双向链表也叫双向表,是链表的一种,它由多个结点组成,每个结点都由一个数据域和两个指针域组成,数据域用来存储数据,其中一个指针域用来指向其后继结点,另一个指针域用来指向前驱结点。
链表的头结点的数据域不存储数据,指向前驱结点的指针域值为null,指向后继结点的指针域指向第一个真正存储数据的结点。

public class TowWayLinkList<T> implements Iterable<T> { //首结点 private Node head; //尾结点 private Node last; //元素总个数 private int n; private class Node { //存储数据 public T item; //指向上一个结点 public Node pre; //指向下一个结点 public Node next; public Node(T item, Node pre, Node next) { this.item = item; this.pre = pre; this.next = next; } } //初始化 public TowWayLinkList() { //初始化首结点 this.head = new Node(null, null, null); //初始化尾结点 this.last = null; //初始化元素个数 this.n = 0; } //清空链表 public void clear() { this.head.next = null; this.head.pre = null; this.head.item = null; this.last = null; this.n = 0; } //获取链表长度 public int length() { return n; } //判断链表是否为空 public boolean isEmpty() { return n == 0; } //获取第一个元素 public T getFirst() { if (isEmpty()) { return null; } return head.next.item; } //获取最后一个元素 public T getLast() { if (isEmpty()) { return null; } return last.item; } //插入元素t public void insert(T t) { //链表为空 if (isEmpty()) { //创建新结点 Node nNode = new Node(t, head, null); //让新结点成为尾结点 last = nNode; //让头结点指向尾结点 head.next = last; } else { //链表不为空 Node oldLast = last; //创建新结点 Node nNode = new Node(t, oldLast, null); //让当前尾结点指向新结点 oldLast.next = nNode; //让新结点成为尾结点 last = nNode; } //元素个数+1 n++; } //向指定位置i处插入元素t public void insert(int i, T t) { //找到i位置的前一个结点 Node pre = head; for (int index = 0; index < i; index++) { pre = pre.next; } //找到i位置的结点 Node curr = pre.next; //创建新结点 Node nNode = new Node(t, pre, curr); //让i位置的前一个结点的下一个结点指向新结点 pre.next = nNode; //让i位置的前一个结点变为新结点 curr.pre = nNode; //元素个数+1 n++; } //获取指定位置i处的元素 public T get(int i) { Node n = head.next; for (int index = 0; index < i; index++) { n = n.next; } return n.item; } //找到元素t在链表中第一次出现的位置 public int indexOf(T t) { Node n = head; for (int i = 0; n.next != null; i++) { n = n.next; if (n.item.equals(t)) { return i; } } return -1; } //删除位置i处的元素,并返回该元素 public T remove(int i) { //找到i位置的前一个结点 Node pre = head; for (int index = 0; index<i; index++) { pre = pre.next; } //找到i位置的结点 Node curr = pre.next; //找到i位置的下一个结点 Node nNode = curr.next; //i位置的前一个结点 的下一个结点 指向 i位置的下一个结点 的 前一个结点 pre.next = nNode; //i位置的下一个结点 的前一个结点 指向 i位置的上一个结点 的 下一个结点 nNode.pre = pre; //元素个数-1 n--; return curr.item; } @Override public Iterator<T> iterator() { return new tIterator(); } public class tIterator implements Iterator { private Node node; public tIterator() { this.node = head; } @Override public boolean hasNext() { return node.next != null; } @Override public Object next() { node=node.next; return node.item; } }}public static void main(String[] args) { //创建双向链表对象 TowWayLinkList<String> sl = new TowWayLinkList<>(); //测试插入 sl.insert("T1"); sl.insert("T2"); sl.insert("T3"); sl.insert(1, "T4"); for (String s : sl) { System.out.println(s); } System.out.println("--------------------------------------"); System.out.println("第一个元素是:" + sl.getFirst()); System.out.println("最后一个元素是:" + sl.getLast()); System.out.println("------------------------------------------"); //测试获取 String getResult = sl.get(1); System.out.println("获取索引1处的结果为:" + getResult); //测试删除 String removeResult = sl.remove(0); System.out.println("删除的元素是:" + removeResult); //测试清空 sl.clear(); System.out.println("清空后的线性表中的元素个数为:" + sl.length());}
循环链表,链表整体要形成一个圆环状。在单向链表中,最后一个节点的指针为null,不指向任何结点,因为没有下一个元素了。
实现循环链表,只需要让单向链表的最后一个节点的指针指向头结点即可。

简单构建
public class CircularLinkedList { public static class Node<T> { T item; Node<T> next; public Node(T item, Node next) { this.item = item; this.next = next; } } public static void main(String[] args) throws Exception { //构建结点 Node<Integer> first = new Node<Integer>(1, null); Node<Integer> second = new Node<Integer>(2, null); Node<Integer> third = new Node<Integer>(3, null); Node<Integer> fourth = new Node<Integer>(4, null); Node<Integer> fifth = new Node<Integer>(5, null); Node<Integer> six = new Node<Integer>(6, null); Node<Integer> seven = new Node<Integer>(7, null); //构建单链表 first.next = second; second.next = third; third.next = fourth; fourth.next = fifth; fifth.next = six; six.next = seven; //构建循环链表,让最后一个结点指向第一个结点 seven.next = first; }}个人博客为:
MoYu's HomePage