为什么要学习手写链表
Java的LinkedList,其实是双向链表,看Node就能看出来
包含size变量,头结点first,尾结点last
各种不同数据结构的CURD操作的基本功,是数据结构与算法的基本功,对于链表,我们要想熟悉它的CURD代码操作,鼠鼠认为,只有自己亲自手写链表,手写链表的定义,创建,删除,遍历,修改,才能最终熟悉其CURD的操作,最后我们刷链表的算法,才能无往而不利,比如反转链表,其实就用到了链表插入的头插法
话不多说,我们直接上代码,我们先从最简单的单链表写起,保证代码言简意赅,让你看完不再迷茫!!!
单链表的一步一步手写
1. 创建Node结点类
// 首先创建单链表的结点类Node,假设存放的是int类型的数值
// 为了简便,我们不使用私有修饰符+get/set的方式,因为这个不重要,后续调用变量只需要“对象.变量名”,适合新手
public class Node {
// 结点的next引用,指向下一个结点
Node next;
// 结点的数值域
int value;
}
2. 创建SingleDirectionLinkedList单向链表类
public class SingleDirectionLinkedList {
// 最简单的单链表,可以只有一个根节点变量,尾结点和size变量都可以没有
Node root;
}
但是这个链表过于简单,我们还需要定义这个SingleDirectionLinkedList中的一些方法
2.1 单链表的新增方法
public void addNode(int val) {
// 链表根节点root为null,插入一个根节点即可
if (root == null) {
root = new Node();
root.value = val;
}else{
// 单链表的根节点不是null,可以选择从根节点开始插入(头插法),也可以选择从末尾插入(尾插法)
// 尾插法可以从根节点遍历到尾部插入,但是那样需要另外的计算机性能消耗,
// 为此我们通常在链表List类中定义一个last结点指向尾结点,就像Java的LinkedList源码做的那样一样
// 我们先使用尾插法+遍历的方式
// 直接使用root结点的引用遍历的话,会造成链表的数据丢失!!!
// 所以我们复制根节点引用temp,用temp帮我们遍历到尾结点
Node temp = root;
// 只要temp的next(下一个结点)不是null,那么temp指向的结点就不是尾结点,继续向下遍历
while(temp.next != null){
temp = temp.next;// 相当于数组下标的i++
}
// 在末尾插入尾结点
Node newNode = new Node();
newNode.value = val;
temp.next = newNode;
}
}
上面是遍历+尾插法新增链表结点的方式,其他的方式,其实大同小异,我推荐大家看这篇文章,写的非常好,我这里只做最简单的代码演示
2.2 单链表的遍历方法
其实刚才已经讲的八九不离十了,我们继续再写一遍
public void forEach() {
if (root == null) {
return;
}
Node temp = root;
while (temp.next != null) {
System.out.println(temp.value);
temp = temp.next;
}
}
链表的循环,代码是非常少的,其实只要搞懂了引用就可以
一生二,二生三,三生万物,本文的主要目的就是链表的那个“一”,只要我们理解了1,后面链表的修改,删除,单链表的last指针尾插法,单链表的头插法,双向链表的创建以及其CURD,都会一通百通。