双向链表最大的特点:
每个节点内有两个数据域(指针),一个pre之前该节点的前一个节点,一个next指向该节点的下一个节点(如果为null,则表示该节点为该链表的末端节点)
双向链表数据类
@Slf4j
public class DoubleLinkedList {
/*头节点,不做存储数据使用*/
private HeroNode2 headNode = new HeroNode2(0, "", "");
/**
* 获取指定编号的节点信息
*
* @param no
*/
public HeroNode2 getByNo(int no) {
if (ObjectUtils.isEmpty(headNode.next)) {
log.info("链表为空");
return null;
}
HeroNode2 cur = headNode.next;
/*根据节点编号获取节点信息*/
while (cur != null) {
if (cur.no == no) {
return cur;
}
}
return null;
}
/**
* 遍历链表
*/
public void list() {
if (headNode.next == null) {
log.info("链表信息为空");
}
HeroNode2 cur = headNode.next;
while (cur != null) {
System.out.println(cur);
cur = cur.next;
}
}
/**
* 添加节点
*
* @param addNode
*/
public void add(HeroNode2 addNode) {
/*将节点直接加在链表的尾部*/
if (ObjectUtils.isEmpty(addNode)) {
log.info("待添加节点为空");
return;
}
HeroNode2 cur = headNode;
/*遍历链表,直到链表末端*/
while (cur.next != null) {
cur = cur.next;
}
cur.next = addNode;
addNode.pre = cur;
}
/**
* 批量添加链表节点
*
* @param addList
*/
public void addList(DoubleLinkedList addList) {
if (addList.length() == 0) {
log.info("待添加的链表为空");
return;
}
/*获取待添加链表的首端元素*/
HeroNode2 addCur = addList.headNode.next;
HeroNode2 cur = headNode.next;
/*找到添加链表的末端元素*/
while (cur.next != null) {
cur = cur.next;
}
/*将添加链表的末端元素的next指向待添加元素的首端元素*/
cur.next = addCur;
/*将待添加元素首端位置的pre域指向添加元素的末端元素*/
addCur.pre = cur;
}
/**
* 按顺序添加节点
*
* @param addNode
*/
public void addByOrder(HeroNode2 addNode) {
if (ObjectUtils.isEmpty(addNode)) {
log.info("待添加的节点内容为空");
return;
}
/*中间变量指向头节点*/
HeroNode2 temp = headNode;
/*标志位,添加的数据编号是否存在,默认不存在*/
boolean flag = false;
while (true) {
/*如果中间节点的next域为空,说明已达链表的末端*/
if (temp.next == null) {
break;
}
/*如果添加的节点的编号和中间节点next域中的编号相同,证明存在数据重复现象*/
if (temp.next.no == addNode.no) {
flag = true;
break;
/*如果中间节点的next域中的编号大于添加节点的编号,说明已找到节点的添加位置*/
} else if (temp.next.no > addNode.no) {
break;
}
/*如果以上条件都不存在,说明还未找到添加位置,需将指针下移*/
temp = temp.next;
}
if (flag) {
log.info("准备插入的英雄编号{}已存在,不能重复添加", addNode.no);
return;
}
/*找到位置之后,添加节点的next域指向中间节点的next域*/
addNode.next = temp.next;
/*待添加节点的pre域指向当前节点*/
addNode.pre = temp;
/*如不是链表末端,则当前节点next域中的pre指向待添加节点*/
if (temp.next != null) {
temp.next.pre = addNode;
}
/*当前节点的next域指向待添加节点*/
temp.next = addNode;
}
/**
* 按顺序添加一个链表
* @param addNodes
*/
public void addListByOrder(DoubleLinkedList addNodes) {
/*循环列表,知道遍历完链表的所有节点为止*/
HeroNode2 cur = addNodes.headNode.next;
HeroNode2 temp ;
while (cur != null) {
/*中间传递值,用于进行添加操作*/
temp = cur;
/*按顺序添加节点*/
addByOrder(temp);
/*节点位置下移*/
cur = cur.next;
}
}
/**
* 更新链表信息
*
* @param updateNode
*/
public void update(HeroNode2 updateNode) {
/*根据节点编号进行数据更新*/
if (ObjectUtils.isEmpty(headNode)) {
log.info("待添加节点为空");
return;
}
/*如果链表为空,则无可更新的数据信息*/
if (headNode.next == null) {
log.info("链表为空");
}
int updateNo = updateNode.no;
/*标志位,用于标志链表中是否包含待更新的数据信息*/
boolean flag = false;
HeroNode2 cur = headNode.next;
while (cur != null) {
if (cur.no == updateNo) {
flag = true;
break;
}
cur = cur.next;
}
if (!flag) {
log.error("未找到待更新的节点");
}
/*更新节点的姓名、昵称信息*/
cur.name = updateNode.name;
cur.nickName = updateNode.nickName;
}
/**
* 根据数据编号删除链表信息
*
* @param no
*/
public void deleteByNo(int no) {
/*如果链表为空,则无可更新的数据信息*/
if (headNode.next == null) {
log.info("链表为空");
return;
}
/*标志位,用于标志链表中是否包含待删除的数据信息*/
boolean flag = false;
HeroNode2 cur = headNode.next;
while (cur != null) {
if (cur.no == no) {
flag = true;
break;
}
cur = cur.next;
}
if (!flag) {
log.error("未找到待删除的节点");
return;
}
/*则修改当前节点的pre域内节点的next域指向当前节点的next域,当前节点的next域可能为null,也可能有值*/
cur.pre.next = cur.next;
/*如果当前节点的next域存在,则直接将当前节点next域内节点的pre域指向当前节点的pre*/
if (cur.next != null) {
cur.next.pre = cur.pre;
}
}
/**
* 获取链表长度
*
* @return
*/
public int length() {
int i = 0;
HeroNode2 cur = headNode.next;
/*当前节点不为空,则链表长度+1*/
while (cur != null) {
i++;
/*每循环一次,指针下移一个位置*/
cur = cur.next;
}
return i;
}
/**
* 反转链表(改变数据结果)
*/
public void reverse(){
/*链表的反转方法,改变链表的数据结构*/
/*如果链表为空或链表只有一个节点直接返回,反转后即是本身*/
if (headNode.next == null || headNode.next.next == null) {
return;
}
/*定义一个中间头节点*/
HeroNode2 tempHead = new HeroNode2(0, "", "");
/*定义该节点指向当前节点的下一个节点,中间存储*/
HeroNode2 next = null;
/*当前节点*/
HeroNode2 cur = headNode.next;
while (cur != null) {
/*获取当前节点的下一个节点,保存节点便于下一次循环*/
next = cur.next;
/*如果头节点的next域不为空,那么next域中值的pre域指向当前节点*/
if(tempHead.next != null){
tempHead.next.pre = cur;
}
/*当前节点的next域指向中间头节点的next域*/
cur.next = tempHead.next;
/*当前节点的pre指向头节点*/
cur.pre = tempHead;
/*头节点的next指向当前节点,完成当前节点的插入操作*/
tempHead.next = cur;
/*cur指向下一个节点,进行下一次循环*/
cur = next;
}
/*原链表的头节点的next域指向中间节点的next域,改变原链表的数据结构*/
headNode.next = tempHead.next;
/*中间头节点的pre域指向中间节点的头节点,改变原链表的数据结构*/
tempHead.pre = headNode;
}
/**
* 反转链表操作(不改变数据结构)
*/
public void reversePrint(){
if(headNode.next == null){
log.info("链表为空");
return;
}
Stack<HeroNode2> stack = new Stack<>();
HeroNode2 cur = headNode.next;
while (cur != null){
stack.push(cur);
cur = cur.next;
}
while (!stack.isEmpty()){
System.out.println(stack.pop());
}
}
}
数据模型
public class HeroNode2 {
public int no;
public String name;
public String nickName;
public HeroNode2 next;//指向链表节点的后一个节点
public HeroNode2 pre;//指向链表节点的前一个节点
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
public HeroNode2(int no, String name, String nickName) {
this.no = no;
this.name = name;
this.nickName = nickName;
}
}
测试类
public class SingleLinkedListDemo {
public static void main(String[] args) {
HeroNode heroNode1 = new HeroNode(1, "宋江", "及时雨");
HeroNode heroNode2 = new HeroNode(2, "卢俊义", "玉麒麟");
HeroNode heroNode3 = new HeroNode(3, "吴用", "智多星");
HeroNode heroNode4 = new HeroNode(4, "公孙胜", "入云龙");
SingleLinkedList singleLinkedList = new SingleLinkedList();
/*普通添加*/
// singleLinkedList.add(heroNode1);
// singleLinkedList.add(heroNode3);
// singleLinkedList.add(heroNode4);
// singleLinkedList.add(heroNode2);
/*按顺序添加*/
singleLinkedList.addByOrder(heroNode1);
singleLinkedList.addByOrder(heroNode2);
/*重复添加*/
singleLinkedList.addByOrder(heroNode2);
singleLinkedList.addByOrder(heroNode3);
singleLinkedList.addByOrder(heroNode4);
/*打印链表*/
System.out.println("添加链表前==========");
singleLinkedList.list();
HeroNode heroNode5 = new HeroNode(5, "关胜", "大刀");
HeroNode heroNode6 = new HeroNode(6, "林冲", "豹子头");
HeroNode heroNode7 = new HeroNode(7, "秦明", "霹雳火");
HeroNode heroNode8 = new HeroNode(8, "呼延灼", "双鞭将");
SingleLinkedList addList = new SingleLinkedList();
addList.add(heroNode6);
addList.add(heroNode5);
addList.add(heroNode8);
addList.add(heroNode7);
System.out.println("带添加的链表==========");
addList.list();
/*测试不带顺序添加链表*/
// singleLinkedList.addList(addList);
/*测试带顺序添加链表*/
singleLinkedList.addListByOrder(addList);
System.out.println("添加链表后==========");
singleLinkedList.list();
/*测试反转*/
System.out.println("反转后的链表============");
/*反转链表,链表的结构发生了该表*/
singleLinkedList.reverse();
singleLinkedList.list();
System.out.println("反转打印链表===============");
singleLinkedList.reversePrint();
System.out.println("链表的有效数据长度:" + singleLinkedList.length());
heroNode4 = new HeroNode(4, "林冲11", "豹子头11");
singleLinkedList.update(heroNode4);
System.out.println("修改后的链表:");
singleLinkedList.list();
singleLinkedList.delete(heroNode4);
singleLinkedList.delete(1);
singleLinkedList.delete("1111");
singleLinkedList.delete(234.56);
System.out.println("删除后的链表:");
singleLinkedList.list();
System.out.println("链表的有效数据长度:" + singleLinkedList.length());
/*0的时候返回倒数第一个节点*/
HeroNode heroNode = singleLinkedList.inDexNode(0);
System.out.println("倒数第一个节点:" + heroNode);
heroNode = singleLinkedList.inDexNode(1);
System.out.println("第一个节点:" + heroNode);
}
}