[Java data structure and algorithm] doubly linked list

Doubly linked list

Analysis of shortcomings of one-way linked list

  1. One-way linked list, the search direction can only be one direction, and the two-way linked list can search forward or backward
  2. The one-way linked list cannot be deleted by itself, it needs to rely on auxiliary nodes, and the two-way linked list can be deleted by itself, so when deleting the one-way linked list node in the previous, you need to find the next node of temp to delete
  3. If you don't understand singly linked list, please refer to-> Single linked list click here

The schematic diagram of the doubly linked list is as follows:
Doubly linked list

Analyze the operation idea of ​​traversing, adding, modifying and deleting doubly linked lists

The traversal method is the same as the one-way linked list, except that it can be added forward or backward
(it is added to the end of the doubly linked list by default)

  1. First find the last node of the doubly linked list
  2. temp.next points to the new node, temp.next = newHeroNode
  3. newHerNOde.pre=temp;

The modification idea is the same as the one-way linked list
deletion

  1. Because it is a two-wire linked list, we can delete a node by ourselves
  2. Find the node to be deleted, such as temp
  3. temp.per.next = temp.next, (point next to the node before temp and the node after temp)
  4. temp.next.pre=temp.pre

Code

package DataType;

public class DoubleLinkedLIstDemo {
    public static void main(String[] args){
        //测试
        System.out.println("双向链表的测试~~~");
        //先创建节点
        HeroNode2 hero1 = new HeroNode2(1, "松江", "及时雨");
        HeroNode2 hero2 = new HeroNode2(2, "卢俊义", "玉麒麟");
        HeroNode2 hero3 = new HeroNode2(3, "吴用", "智多星");
        HeroNode2 hero4 = new HeroNode2(4, "林冲", "豹子头");
        //创建一个双向链表
        DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
        doubleLinkedList.add(hero1);
        doubleLinkedList.add(hero2);
        doubleLinkedList.add(hero3);
        doubleLinkedList.add(hero4);
        doubleLinkedList.list();
        //修改测试
        HeroNode2 newHeroNode = new HeroNode2(4, "董小宇", "董小宇");
        doubleLinkedList.update(newHeroNode);
        System.out.println("修改后的链表是~~~");
        doubleLinkedList.list();
        //删除测试
        doubleLinkedList.del(3);
        System.out.println("删除后的链表情况~~~");
        doubleLinkedList.list();
        //测试按照顺序添加
        HeroNode2 addHeroNode = new HeroNode2(3, "董大宇", "董大宇");
        doubleLinkedList.addByOrder(addHeroNode);
        System.out.println("按照顺序后的链表情况~~~");
        doubleLinkedList.list();
    }
}
//创建一个双向链表的类
class DoubleLinkedList{
    ///先初始化一个头节点,头节点不要动,固定的位置,不存放具体的数据
    private HeroNode2 head = new HeroNode2(0,"","");
    //返回头节点
    public HeroNode2 getHead(){
        return head;
    }
    //遍历双向链表的方法
    public 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 = temp.next;
        }
    }
    //添加一个节点,到双向链表的最后
    public void add(HeroNode2 heroNode){
        //因为head不能动,因此我们需要一个辅助变量 temp
        HeroNode2 temp = head;
        //遍历链表,找到最后
        while (true){
            //找到链表的最后
            if (temp.next == null){
                break;
            }
            //如果没有找到最后,就将temp后移
            temp = temp.next;
        }
        //当推出while循环时,temp就指向了链表的最后
        //构成一个双向链表
        temp.next = heroNode;
        heroNode.pre = temp;
    }
    //添加数据,按照顺序来
    public void addByOrder(HeroNode2 heroNode){
        //还是因为头节点不能动,我们仍然通过辅助指针来帮助
        //因为双向链表,因此我们找的temp
        HeroNode2 temp = head;
        boolean flag = false;//标志添加的编号是否存在,默认为false
        while (true){
            if (temp.next == null){//说明temp在链表最后
                break;//
            }
            if (temp.next.no > heroNode.no){//位置找到了,就在temp的后面输入
                break;
            }else if (temp.next.no == heroNode.no){//说明添加数据的编号已经存在了
                flag = true;//说明编号存在、
                break;
            }
            temp = temp.next;//后移,相当于遍历
        }
        //判断flag的值
        if (flag){//如果为真,就不能添加,说明编号存在
            System.out.printf("准备插入英雄编号%d已经存在,不能加入\n",heroNode.no);
        }else{
            //插入到链表当中,temp的后面
            heroNode.next = temp.next;
            temp.next = heroNode;
            heroNode.pre = temp.next.pre;
            temp.next.pre = heroNode;
        }
    }
    //修改一个节点的内容,可以看到双向链表节点修改和单向链表一样,只是类型不一样,
    public void update(HeroNode2 heroNode){
        //判断是否为空
        if (head.next == null){
            System.out.println("链表为空!");
            return;
        }
        //找到需要修改的节点,根据no编号查找
        //定义一个temp辅助变量
        HeroNode2 temp = head.next;
        boolean flag = false;//表示是否找到该节点
        while (true){
            if (temp == null){
                break;//到链表最后了,没有数据了,已经遍历结束了
            }
            if (temp.no == heroNode.no){
                //找到了节点
                flag = true;
                break;
            }
            temp = temp.next;
        }
        //根据flag判断是否找到要修改的节点
        if (flag){
            temp.name = heroNode.name;
            temp.nickName = heroNode.nickName;
        }else {//没有找到节点
            System.out.printf("没有找到编号%d的节点,不能修改\n",heroNode.no);
        }
    }
    //从双向链表中删除一个节点
    //说明
    //1.对于双向链表,可以直接找到要删除的节点
    //2.找到后自我删除即可
    public void del(int no){
        //判断当前当前列表是否为空
        if (head.next == null){//空链表
            System.out.println("链表空,无法删除!");
            return;
        }
        HeroNode2 temp = head.next;//辅助指针
        boolean flag = false;//标记是否找到需要删除的节点
        while (true){
            if (temp == null){//说明遍历结束,已经到最后了
                break;
            }
            if (temp.no == no){
                //说明找到了需要删除的节点temp
                flag = true;
                break;
            }
            temp = temp.next;//temp后移进行遍历
        }
        //判断flag
        if (flag){
            //找到,可以删除
            //相当于把需要删除的节点排除出去了
            temp.pre.next = temp.next;
            if (temp.next != null) {
                //代码有弊端,然后是最后一个节点,就不需要执行下面这句话,不然会空指针异
                temp.next.pre = temp.pre;
            }
        }else{
            System.out.printf("要删除的%d节点不存在",no);
        }
    }
}

//定义一个HeroNode2,每个HeroNode对象就是一个节点
class HeroNode2{
    public int no;
    public String name;
    public String nickName;
    public HeroNode2 next;//指向下一个节点,默认为null
    public HeroNode2 pre;//指向前一个节点,默认为null
    //构造器
    public HeroNode2(int no,String name,String nickName){
        this.no = no;
        this.name = name;
        this.nickName = nickName;
    }
    //为了显示方法,我们重新toString
    @Override
    public String toString() {
        return "[HeroNode2{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", nickName='" + nickName + "]";
    }
}

I am also a beginner in programming, and it is inevitable that there is a mistake in understanding. I hope that after reading, you can comment out the errors, thank you

Published 20 original articles · praised 211 · 10,000+ views

Guess you like

Origin blog.csdn.net/lolly1023/article/details/105453604