单链表
序言
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针实现的。
链表由一系列结点组成,结点可以在运行时动态生成,而且由于没有闲置的内存,因此空间效率比数组高。
其插入操作可达到O(1)复杂度,但是查找或者访问特定的结点复杂度是O(n)。
链表的实现可以是单向链表或者双向链表,LinkedList的底层就是双向链表,本文介绍单向链表的简单操作。
带头结点
不带头结点
Java指针
栈中的变量指向堆内存中的变量,这就是Java中的指针。
https://zhuanlan.zhihu.com/p/131612029
Java自引用
自引用是构造链表的基础,就是在类里定义一个指向自身的引用。
public class Node { public Object data; public Node next;//java的引用就是C语言的指针 public Node(Object data) { this.data=data; } public static void main(String args[]) { //两个Node Node node1=new Node("张三"); Node node2=new Node("李四"); //由于Java语言中没有指针,因此可以将每个结点包装成类,利用其中一个成员属性将一个一个单独的结点连接起来。 node1.next=node2; System.out.println(node1.data); System.out.println(node1.next.data); } }
Node
由于Java语言中没有指针,因此可以将每个结点包装成类,利用其中一个成员属性将一个一个单独的结点连接起来。
Java指针已经被抽象成了引用,引用可以看成是一个功能受限的指针(或者说被阉割的指针)
对于数据结构,语言的选择不会影响它的表达,真正理解它的意义才更为重要。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class Node<T> //单链表结点类,T指定结点的元素类型 { public T data; //数据域,存储数据元素 public Node<T> next; //地址域,引用后继结点 public Node(T data, Node<T> next) //构造结点,data指定数据元素,next指定后继结点 { this.data = data; //T对象引用赋值 this.next = next; //Node<T>对象引用赋值 } public Node() { this(null, null); } public String toString() //返回结点数据域的描述字符串 { return this.data.toString(); } }
temp指针指向头结点headNode,此时temp指针等价于headNode。
public Node<E> headNode;
Node<E> temp = headNode;
增
尾部插入
头部插入
中间插入
删
尾部删除
头部删除
中间删除
改
查
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public String toString(){ StringBuilder sb=new StringBuilder(); if (headNode==null){ return "无数据"; }else { Node<T> temp = headNode; sb.append(temp.data+"\n"); while(temp.next != null) { sb.append(temp.next.data+"\n"); temp = temp.next;//将指针移动到下一个结点 } } return sb.toString(); }