Two-way linked list of data structure and algorithm

Two-way linked list of data structure and algorithm

For singly linked lists, please refer to my other blog post
https://blog.csdn.net/hcyxsh/article/details/114101200

1. Operation analysis and realization of doubly linked list

Use a doubly linked list with head to achieve-Water Margin Hero Ranking

Analysis of the disadvantages of managing singly linked lists:

  1. For singly linked lists, the search direction can only be one direction, while doubly linked lists can be searched forward or backward.

  2. A singly linked list cannot be deleted by itself and needs to rely on an auxiliary node, while a doubly linked list can be deleted by itself, so when we delete a singly linked list, we always find temp, which is the previous node of the node to be deleted (carefully understand).

  3. Analyzed how to complete the traversal, add, modify and delete the doubly linked list
    Insert picture description here
    . Explanation of the above figure:

Analyze the traversal, add, modify, and delete operation ideas of the doubly linked list === "code implementation

  1. The traversal party is the same as the singly linked list, except that it can be searched forward or backward

Add one (the default is added to the end of the doubly linked list)

(1) First find the last node of the doubly linked list

(2) temp.next = newHeroNode

(3) newHeroNode.pre = temp;
add two: orderly add
(1) find the next node added
(2) determine the size relationship of the serial number

heroNode.next = temp.next;
if (temp.next != null){//The first and last one, there will be a null pointer exception
temp.next.pre = heroNode;
}
temp.next = heroNode;
heroNode.pre = temp;

  1. The modification idea is the same as the original singly linked list.

  2. delete

(1) Because it is a doubly linked list, we can delete a node by ourselves

(2) Find the node to be deleted directly, such as temp

(3) temp.pre.next = temp.next

(4) temp.next.pre = temp.pre;

2. Code implementation of doubly linked list

package com.datastrucate.linkedlist;

/**
 * ClassName:SingleLinkedList
 * Package:com.datastrucate.linkedlist
 * Description:
 * 用水浒传英雄模拟单链表的CRUD
 *
 * @Date:2021/2/25 17:01
 * @Author:hm
 */
public class DoubleLinkedListDemo {
    
    

    public static void main(String[] args) {
    
    

        //先创建节点

        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(hero4);
//
//        doubleLinkedList.add(hero2);
//
//    	doubleLinkedList.add(hero3);

        doubleLinkedList.addOrder(hero1);

        doubleLinkedList.addOrder(hero4);
//
        doubleLinkedList.addOrder(hero2);

        doubleLinkedList.addOrder(hero3);

    	//显示链表
        doubleLinkedList.list();

//        doubleLinkedList.update(new HeroNode2(1,"宋小江","及时雨"));
//        System.out.println("更新后");
//        doubleLinkedList.list();
//
//        doubleLinkedList.delete(1);
//        System.out.println("删除后");
//        doubleLinkedList.list();


    }

}

//单链表类
class DoubleLinkedList{
    
    

    private HeroNode2 head = new HeroNode2(0,"","");//头结点,不带数据,不可移动

    //获取头结点
    public HeroNode2 getHead() {
    
    
        return head;
    }

    /**
     * 添加方法一:不带顺序的添加,添加到末尾
     */
    public void add(HeroNode2 heroNode){
    
    

        HeroNode2 temp = head;//临时节点,用于避免移动头结点
        //遍历到节点末尾
        while(true){
    
    

            if (temp.next == null){
    
    //空链表,可以添加
                break;
            }
            //没找到,指针后移
            temp = temp.next;
        }
        //退出循环代表,此时temp指针在最后面
        //添加新节点到最后面
        temp.next = heroNode;
        heroNode.pre = temp;

    }

    /**
     * 第二种添加:
     * 带顺序添加
     */
    public void addOrder(HeroNode2 heroNode){
    
    

        //temp  是位于 添加位置的前一个节点
        HeroNode2 temp = head;//临时节点,用于避免移动头结点
        boolean flag = true ;//用于标记可以添加
        //遍历
        while (true){
    
    
            if (temp.next == null){
    
    //空链表
                break;
            }
            if (temp.next.no > heroNode.no){
    
    //序号在temp下一个节点前,能添加

                break;
            }else if (temp.next.no == heroNode.no){
    
    //序号存在,不能添加
                flag = false;
                break;
            }
            //指针后移
            temp = temp.next;
        }
        //判断flag
        if (flag){
    
    //可以添加


            //以第一节点为例:temp.next=null
            heroNode.next = temp.next;
            if (temp.next != null){
    
    //第一个和最后一个,会出现空指针异常

                temp.next.pre = heroNode;
            }
            temp.next = heroNode;
            heroNode.pre = temp;

        }else {
    
    //不能添加

            System.out.println("链表已经存在该英雄,不能添加");
        }

    }

    /**
     * 更新节点
     *
     */
    public void update(HeroNode2 heroNode){
    
    

        if (head.next == null){
    
    
            System.out.println("链表为空");
        }

        HeroNode2 temp = head.next;//头节点的后一节点
        boolean flag = false;//用于标记是否更新
        //遍历
        while (true){
    
    

            if (temp == null){
    
    //空链表
                break;
            }
            if (temp.no == heroNode.no){
    
    //更新
                flag = true;
                break;
            }

            //指针后移
            temp = temp.next;
        }
        //更新
        if (flag){
    
    

            temp.name = heroNode.name;
            temp.nickname = heroNode.nickname;
        }else {
    
    
            System.out.println("没有找到编号为"+heroNode.no+"的英雄");
        }
    }

    /**
     * 删除节点
     * 思路
     * 1. head 不能动,因此我们需要一个 temp 辅助节点找到待删除节点
     * 2. 说明我们在比较时,是 temp.no 和 需要删除的节点的 no 比较
     * 注意:删除最后一个节点的空指针问题
     */
    public void delete(int no){
    
    

        if (head.next == null){
    
    
            System.out.println("链表为空");
        }
        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;
            if (temp.next != null){
    
    //最后一个节点temp.next=null,避免出现空指针异常

                temp.next.pre = temp.pre;
            }

        }else {
    
    
            System.out.println("不存在该节点,不能删除");
        }
    }


    /**
     * 显示所有节点信息
     */
    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.next;
        }

    }
}

//实体类
class HeroNode2{
    
    
    public int no;//英雄编号
    public String name;//姓名
    public String nickname;//昵称
    public HeroNode2 next;//指向下一节点的指针
    public HeroNode2 pre;//指向前一节点

    public HeroNode2(int no,String name, String nickname){
    
    
        this.no = no;
        this.name = name;
        this.nickname = nickname;
    }

    @Override
    public String toString() {
    
    
        return "HeroNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", nickname='" + nickname + '\'' +
                '}';
    }
}

Guess you like

Origin blog.csdn.net/hcyxsh/article/details/114143241