目录
双向链表的基本操作详解https://blog.csdn.net/qq_24016309/article/details/121163375
一.结点的定义
在c语言中,我们使用一个结构体来定义一个结点。但是在java中,我们使用一个类(class)来定义结点。
其中data表示当前结点中存放的数据,next表示当前结点的下一个结点。这里还定义了一个构造方法用于初始化data的值。
public class Node {
public int data;
public Node next;
public Node(int data){
this.data = data;
}
}
二.单链表的定义
这里我们定义的单链表为不带头结点的非循环单链表,但是要有一个虚拟的头结点,来表示我们这个单链表的第一个结点。
public class MyLinkedList { //不带头结点
public Node head ; //这个不算头结点,算是这个链表的第一个节点
}
三.单链表的操作
下面要介绍的是单链表的相关操作,这些函数放在上面的单链表MyLinkdeList中。经测试,所有功能均能正确实现
1.头插法
就是在最前插入,注意对链表为空的特判
先创建一个node,把数据放进这个node,再把这个node头插
public void addFirst(int data){
Node node = new Node(data);
if(this.head == null){ //注意这里要进行特判
this.head = node;
}else {
node.next = this.head;
this.head = node;
}
}
2.尾插法
就是在最后面插入,注意对链表为空的特判
先创建一个node,把数据放进这个node,再把这个node尾插
注意:和头插法不同的是,要在链表的尾部插入,首先要做的就是找到链表的最后一个结点,链表的最后一个结点的next是null,所以循环退出条件就是cur.next == null,我们用一个while循环和一个当前结点的引用cur遍历到最后一个结点,然后让最后一个结点的next为我们要插入的node结点即可
public void addLast(int data){
Node node =new Node(data);
if(this.head == null){
this.head = node;
}else {
Node cur = this.head;
while (cur.next != null){
cur = cur.next;
}
cur.next = node;
}
}
3.任意位置插入(第一个数据节点为0号下标 )
就主要是对index的特判,如果index不合法(<0或者>length),返回false,若index为0,那就是头插,若Index为length,那就是尾插。
其他位置写一个找到index所对应结点的前一个结点的函数Node pre=searchPrev(index),然后将结点插入到这个pre结点之后就行了。
public boolean addIndex(int index,int data){
int len = this.size();
if (index > len ||index < 0){ //对index合法性特判
return false;
}
if(index == 0){ //当在头部插入时,使用头插法
this.addFirst(data);
return true;
}
if (index == len){ //当在尾部插入时,使用尾插法
this.addLast(data);
return true;
}else {
Node p = this.searchPrev(index); //找到index所对应结点的前一个结点
Node node = new Node(data);
node.next = p.next;
p.next = node;
return true;
}
}
searchPrev(int index)函数:head为第一个结点,它的index值为0
如果我们要找到下标1所对应的结点,即第2个结点,那么从第一个结点head开始,执行1轮循环,即执行一次p = p.next即可。
如果我们要找到下标3所对应的结点,即第4个结点,那么从第一个结点head开始,执行3轮循环,即执行三次p = p.next即可。
............................
如果我们要找到下标Index所对应的结点,即第index+1个结点,那么从第一个结点head开始,执行index轮循环,即执行index次p = p.next即可。
现在我们要查找下标为Index的前一个结点,即下标为index的结点
如果我们要找到下标Index-1所对应的结点,即第index个结点,那么从第一个结点head开始,执行index-1轮循环,即执行index-1次p = p.next即可。
所以执行index-1轮循环即可
public Node searchPrev(int index){ //返回index所对应结点的前一个结点
Node p = this.head;
int count = 0;
while(count < index-1){
p = p.next;
count++;
}
return p;
}
4.查找是否包含关键字key是否在单链表当中
这个就很简单了,直接一轮循环结束
public boolean contains(int key){
Node p = this.head;
while(p != null){
if(p.data == key){
return true;
}
p = p.next;
}
return false;
}
5.得到单链表的长度
这个也是非常简单,一轮循环结束
public int size(){
Node p = this.head;
int len = 0;
while (p != null){
p = p.next;
len++;
}
return len;
}
6.打印单链表
也是一轮循环结束,这里我是每个结点的数据一行这样打印了,也可以打印成一行
public void display(){
Node cur = head;
while (cur != null){
System.out.println(cur.data);
cur = cur.next;
}
}
7.删除第一次出现关键字为key的节点
主要还是一些特判,1.链表为空;2.key值为头结点上的data;
注意特判里面要return,以为只需要删除第一次出现的结点。
其他的位置,参考下面的删除全部关键字为Key的结点的讲解,找到data=key就break即可。
public void remove(int key){
if (this.head == null){
System.out.println("链表为空");
return;
}
if(this.head.data == key){
this.head = this.head.next;
return;
}
Node pre = head;
Node cur = head.next;
while(cur != null){
if(cur.data == key){
pre.next = cur.next;
break;
}else {
pre = cur;
}
cur = cur.next;
}
}
8.删除所有值为key的节点
这个就比较重要了,要弄明白
- 首先就是特判,和前面一样,1.链表为空;2.key值为头结点上的data,但是这里要注意一点,对key值是不是为头结点上的data的值这个判定不能放在前面,必须放在最后
因为,比如你要删除2,如果第一个结点和第二个结点都是2,那你处理完第一个结点,第二个结点还是2,此时的头结点还是2,但是头结点的处理只有一次。所以这里要将对头结点的处理放到最后面去,等到我们先把除了头结点以外其他的data=2的结点删除了,再去判断头结点也是2的情况。
如图所示,一开始有三个2,我们先将除了头结点以外的2先删除了,再去对头结点进行删除,此时便不会再有多余的2。
- 然后要注意的就是如何将后面的2都删除,
这里我们定义两个Node类型的引用,pre代表头结点,cur代表头结点的下一个结点,如图所示,我们的目的是要删除所有的2
然后开始判断,如果cur.data==key,这里key=2,满足条件,那就执行删除操作,让pre.next = cur.next,然后cur = cur.next
else,也就是如果cur不是我们要删除的结点,我们就让pre = cur,把pre拉过来,然后cur = cur.next
就这样一直进行循环,直到最后cur=null退出循环。
public void removeAllKey(int key){
if (this.head == null){
System.out.println("链表为空");
}
Node pre = head;
Node cur = head.next;
while(cur != null){
if(cur.data == key){
pre.next = cur.next;
cur = cur.next;
}else {
pre = cur;
cur = cur.next;
}
}
if(this.head.data == key){ //如果本来的第二个结点还是key呢,这个必须放到后面
this.head = this.head.next;
}
}