继上文 数据结构之链表1之后,本文将继续讲解链表。
循环单链表
循环单链表是另一种形式的单链表。它的特点是表中的最后一个结点的指针域指向头结点,整个链表形成一个环。因此,从循环单链表中任一结点出发均可找到表中其他结点,如下图。
类似的,还可以有多重链的循环链表。
循环单链表的底层实现
循环单链表的操作与单链表的实现基本一致,差别仅在于循环单链表每一个结点都能访问到其后继结点。
MyLoopNode 是这里定义的一个结点类。
- void removenext() 删除当前结点的下一个结点
- void after() 在当前结点后插入一个结点
- MyLoopNode next() 获取当前结点的下一个结点
- int getData() 获取当前结点的信息
package util;
public class MyLoopNode {
//循环链表
//结点内容
int data;
//下一个结点就是它自己
MyLoopNode next=this;
public MyLoopNode(int data) {
this.data = data;
}
//删除下一个结点
public void removenext() {
//取出当前结点的下下个结点
MyLoopNode newNext = this.next.next;
//把下下个结点设置为当前节点的下一个结点
this.next = newNext;
}
//插入一个节点作为当前节点的下一个节点
public void after(MyLoopNode node) {
//取出当前节点的下一个节点
MyLoopNode nextNext = this.next;
//把新节点作为当前节点的下一个节点
this.next = node;
//把此时当前节点的下下个节点设置为新节点的下一个节点
node.next = nextNext;
}
//获取下一个结点
public MyLoopNode next() {
return this.next;
}
//获取当前结点的信息
public int getData() {
return this.data;
}
}
简单Test:
package classify;
import util.MyLoopNode;
public class LoopListTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建节点(每一个节点都是单一的循环链表)
MyLoopNode n1 = new MyLoopNode(1);
MyLoopNode n2 = new MyLoopNode(2);
MyLoopNode n3 = new MyLoopNode(3);
//增加节点
n1.after(n2);
n2.after(n3);
//查看
System.out.println(n1.next().getData()); // 2
System.out.println(n1.next().next().getData()); // 3
System.out.println(n1.next().next().next().getData()); // 1
//删除结点
n1.removenext(); //删除值为 2 的结点
System.out.println(n1.next().getData()); // 3
System.out.println(n1.next().next().getData()); //1
}
}
双链表
前面的链表的结点中都只有一个指示直接后继的指针域,由此,从链表的某个结点出发只能顺指针往后寻查其他结点。若需要直接查找结点的直接前驱,则需要先标记该结点,然后从表头结点出发遍历链表。
为了克服单链表这种单向性的缺点,可利用双链表。
双链表的结点中有两个指针域,其一指向直接后继,另一指向直接前驱。
双链表的基本实现与单链表差不多,唯一需要多注意的是每次对结点进行处理要同时考虑其前驱指针域和后继指针域。
这里稍微介绍一下循环双链表。
循环双链表的底层实现
MyDoubleNode 是这里定义的循环双链表的结点类(同时也是一个只有一个结点的循环双链表)
- void after(MyDoubleNode node) 向当前结点后插入一个结点
- MyDoubleNode next() 访问当前结点的下一个结点
- MyDoubleNode pre() 访问当前结点的上一个结点
- int getDate() 获取当前结点的信息
package util;
public class MyDoubleNode {
//循环双链表
//上一个结点
MyDoubleNode pre=this;
//下一个结点
MyDoubleNode next=this;
//结点数据
int data;
public MyDoubleNode(int data) {
this.data=data;
}
//增加结点
public void after(MyDoubleNode node) {
//当前节点的下一个节点
MyDoubleNode nextNext = next;
//把新节点作为当前节点的下一个节点
this.next=node;
//把当前节点作为新节点的上一个节点
node.pre=this;
//让当前节点原来的下一个节点作为新节点的下一个节点
node.next=nextNext;
//让当前节点原来的下一个节点的上一个节点为新节点
nextNext.pre=node;
}
//下一个结点
public MyDoubleNode next() {
return this.next;
}
//上一个结点
public MyDoubleNode pre() {
return this.pre;
}
//获取当前结点的值
public int getData() {
return this.data;
}
}
简单Test:
package classify;
import util.MyDoubleNode;
public class DoubleListTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建节点(每一个节点都是一个循环双链表)
MyDoubleNode n1 = new MyDoubleNode(1);
MyDoubleNode n2 = new MyDoubleNode(2);
MyDoubleNode n3 = new MyDoubleNode(3);
//添加节点(组合成一个循环双链表)
n1.after(n2);
n2.after(n3);
//查看上一个 1,自己本身 2,下一个节点 3的内容
System.out.println(n2.pre().getData()); // 1
System.out.println(n2.getData()); // 2
System.out.println(n2.next().getData()); // 3
//查看表头的上一个结点的值
System.out.println(n1.pre().getData()); // 3
}
}