使用带head头的双向链表实现-水浒传排行榜管理
单链表的缺点:
1.单链表,查找的方向只能是一个方向,而双向链表可以
向前或向后查找
2.单链表不能自我删除,需要靠辅助节点(指针),而双向
链表,则不用辅助指针,所以前面我们单链表删节点,
总是找到temp,temp是待删除节点的前一个接点
3.示意图帮助理解删除
双向链表代码如下:
// 定义DoubleLinkedList 管理英雄
class DoubleLinkedList {
// 先初始化头结点,头结点不要动(改变头结点将无法找到后续节点)
private HeroNode head = new HeroNode(0, "", "");
public HeroNode getHead() {
return head;
}
public void setHead(HeroNode head) {
this.head = head;
}
// 和单链表方法几乎一样
public void add(HeroNode heroNode) {
// 因为head节点不能动,因此我们需要一个辅助变量temp
HeroNode temp = head;
// 遍历链表,找到最后
while (true) {
// 找到链表的最后
if (temp.next == null) {
break;
}
// 如果没有找到最后,将temp后移
temp = temp.next;
}
// 当退出while循环时,temp就指向了链表的最后
// 形成一个双向链表
temp.next = heroNode;
heroNode.pre = temp;
}
// 方法和单链表一样
// 修改节点的信息,根据no编号来修改,即no编号不能改
// 说明
// 1.根据newHeroNode的no来修改即可
public void update (HeroNode newHeroNode) {
// 判断是否空
if (head.next == null) {
System.out.println("链表为空~");
return;
}
// 找到需要修改的节点,根据no编号来找
// 定义一个辅助变量
HeroNode 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.name = newHeroNode.name;
temp.nickname = newHeroNode.nickname;
} else { // 没有找到需要修改的节点
System.out.printf("没有找到编号%d的节点\n", newHeroNode.no);
}
}
// 删除双向链表节点的代码
public void del(int no) {
// 为什么要这么做,因为删除双向链表不需要找到
// 待删除节点的前一个节点temp
// 只需要找到需要删除的节点,自己删除即可
// 判断当前链表是否为空
if (head.next == null) {
System.out.println("链表为空,无法删除~");
return;
}
// 辅助指针
HeroNode cur = head.next;
boolean flag = false; // 标识是否找到待删除的节点
while (true) {
if (cur == null) {// 已经到链表最后节点的next
break;
}
if (cur.no == no) {
// 找到了待删除节点cur
flag = true;
break;
}
cur = cur.next; // temp后移,遍历
}
// 判断flag
if (flag) {// 找到了
cur.pre.next = cur.next;
// 如果是最后一个节点,就不需要执行下面,否则会出现空指针异常
if (cur.next != null) {
cur.next.pre = cur.pre;
}
} else {
System.out.printf("要删除的节点%d不存在~\n", no);
}
}
// 显示链表【遍历】
// 方法和单链表一样
public void list() {
// 判断链表是否为空
if (head.next == null) {
System.out.println("链表为空");
return;
}
// 因为头节点不能动,因此需要辅助变量来遍历
HeroNode temp = head.next;
while (true) {
// 判断是否到链表最后
if (temp == null) {
break;
}
// 输出节点信息
System.out.println(temp);
// 将temp后移,一定小心,不后移会造成死循环
temp = temp.next;
}
}
}
// 定义HeroNode,每个HeroNode对象就是一个节点
class HeroNode {
public int no;
public String name;
public String nickname;
// 指向下一个节点,默认是null
public HeroNode next;
// 指向上一个节点,默认是null
public HeroNode pre;
// 构造器
public HeroNode(int no, String name, String nickname) {
this.no = no;
this.name = name;
this.nickname = nickname;
}
// 为了显示方便,重写toString
@Override
public String toString() {
return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";
}
}
public void addByOrder(HeroNode heroNode) {
// 按照单链表的顺序添加思路
// 空链表
if (head.next == null) {
heroNode.pre = head;
head.next = heroNode;
return;
}
HeroNode temp = head;
HeroNode next = null;
while (true) {
if (temp.next == null) {// 遍历到双链表尾部
temp.next = heroNode;
heroNode.pre = temp;
break;
}
if (temp.next.no > heroNode.no) {// 找到要插入的位置
next = temp.next;
temp.next = heroNode;
heroNode.pre = temp;
if (next != null) {
heroNode.next = next;
next.pre = heroNode;
}
break;
}
if (temp.next.no == heroNode.no) {// 找到相同的节点
System.out.printf("要插入的no=%d已经存在\n", heroNode.no);
break;
}
temp = temp.next;
}
}