双向链表
双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。
双向链表的逻辑结构
双向链表的CURD实现
定义一个节点
class HeroNode2{
public int no;
public String name;
public String nickName;
public HeroNode2 next; // next域
public HeroNode2 pre;
public HeroNode2(int no,String name,String nickName){
this.name = name;
this.nickName = nickName;
this.no = no;
this.next = null;
this.pre = null;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
}
定义类来管理节点信息
class BothWayLinkedList{
// 头节点
private static HeroNode2 head = new HeroNode2(0,null,null);
// 返回头节点
public HeroNode2 getHead() {
return head;
}
- 定义一个头节点
- 定义一个方法可以返回头节点
查询所有节点信息
思路
- 定义一个辅助节点
- 遍历链表,将每个节点赋予辅助节点
- 判断辅助节点是否为NULL
- 输出辅助节点
代码实现
public static void list(){
// 先判断链表是否为空
if(head.next == null){
System.out.println("链表为空");
return;
}
// 因为头节点不能动,我们需要一个辅助遍历来遍历
HeroNode2 temp = head.next;
//开始遍历
while(true){
// 先判断是否到链表的最后
if(temp == null){
break;
}
// 输出节点的信息
System.out.println(temp);
temp = temp.next;
}
}
添加节点信息(从末尾添加)
思路
- 遍历链表到最后一个节点
- 添加节点至最后一个节点后
代码实现
// 添加数据 (到末尾)
public void add(HeroNode2 heroNode){
// 添加的时候要想办法找到链表的尾节点,让尾节点的next指向heroNode
// 因为head节点不能动,因此我们需要一个辅助节点temp
HeroNode2 temp = head;
// 遍历链表,找到最后
while(true){
// 找到了最后一个节点
if(temp.next == null){
break;
}
// 如果不是最后一个节点
temp = temp.next;
}
// 添加操作
temp.next = heroNode;
heroNode.pre = temp;
}
按照no大小进行按顺序进行添加
思路
- 首先先判断head.next是否为空,如果为空,则直接添加到head后
- 判断是否有重复节点
- 寻找新节点的no是否处于已存在节点的no之间
- 判断temp.next是否为空
- 上述1,2,3,4的顺序不能颠倒,否则会出现问题
代码实现
public void addByNo(HeroNode2 heroNode){
HeroNode2 temp = head.next;
while (true){
if (temp == null){
head.next = heroNode;
heroNode.pre = head;
// temp.pre.next = heroNode;
// heroNode.pre = temp.pre;
break;
}
if (temp.no == heroNode.no){
System.out.println("已存在添加的编号,无法添加");
break;
}
if ((heroNode.no > temp.pre.no) && (heroNode.no <temp.no)){
heroNode.next = temp;
heroNode.pre = temp.pre;
temp.pre.next = heroNode;
temp.pre = heroNode;
break;
}
if (temp.next == null){
temp.next = heroNode;
heroNode.pre = temp;
break;
}
temp = temp.next;
}
}
修改节点内容
思路
- 遍历节点
- 判断是否有no相同的节点,有则修改
- 判断temp是否为null,为null则退出
代码实现
public void update(HeroNode2 newHeroNode){
if (head.next == null){
System.out.println("链表为空");
return;
}
HeroNode2 temp = head.next;
// 表示是否找到该节点
boolean flag = false;
while (true){
if (temp == null){
break;
}
if (temp.no == newHeroNode.no){
flag = true;
break;
}
temp = temp.next;
}
if (flag){
temp.nickName = newHeroNode.nickName;
temp.name = newHeroNode.name;
}else {
System.out.println("没有匹配的节点信息");
}
}
节点的删除
思路
- 遍历节点
- 找到删除节点
- 修改删除节点的pre节点的指针和next节点的指针走向
代码实现
public void delete(int no){
HeroNode2 temp = head.next;
// 是否找到待删除节点
boolean flag = false;
while (true){
if (temp == null){
break;
}
if (temp.no == no){
flag = true;
break;
}
temp = temp.next;
}
if (flag){
temp.pre.next = temp.next;
// temp.next.pre = temp.pre;这一块的代码有问题,加入删除的是最后一个节点,则会出现空指针异常
if (temp.next != null){
temp.next.pre = temp.pre;
}
}else {
System.out.println("找不到节点信息");
}
}