[java]-Algorithms and Data Structures-Chapter 4-Linked Lists

4. Linked list

1 Introduction

A linked list is an ordered list, but it is stored in memory as follows

insert image description here

  1. The linked list is stored in the form of nodes, which is a chain storage
  2. Each node contains data field, next field: points to the next node.
  3. As shown in the figure: It is found that each node of the linked list is not necessarily stored continuously
  4. The linked list is divided into a linked list with a head node and a linked list without a head node, which are determined according to actual needs

Singly linked list (leading node) logical structure diagram:

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-xKf3sdi9-1649340941711)(https://secure2.wostatic.cn/static/uPyAcsmSPWx5wPBJSQjFDJ/image.png)]

2. Application examples of singly linked list

Use a one-way linked list with a head to implement – ​​Water Margin Hero Ranking Management to complete the operation of adding, deleting, modifying and checking heroes

1) Add the tail of the linked list

Analysis:
First create a Head node, which is to represent the head of the singly linked
list. Every time a node is added later, it is added to the last position of the linked list.

  1. Define HeroNodes
@Data
@ToString
class HeroNode{
    
    
    private int no;
    private String name;
    private String nickName;
    private HeroNode next;

    public HeroNode(int no,String name,String nickName){
    
    
        this.no = no;
        this.name = name;
        this.nickName = nickName;
    }
}
  1. Define SingleLinkedList¶
class SingleLinkedList {
    
    

    // 初始化头结点 不存放具体的数据
    private final HeroNode head = new HeroNode(0, "", "");

    // 遍历链表
    public void list() {
    
    

        // 头结点不能动,因此需要辅助变量遍历
        HeroNode temp = head.next;
        while (true) {
    
    
            if (temp == null) {
    
    
                break;
            }
            System.out.println(temp);
            // temp 后移
            temp = temp.next;
        }
    }

    // 第一种:不考虑排序
    public void add(HeroNode heroNode) {
    
    

        HeroNode temp = head;

        while (temp.next != null) {
    
    
            temp = temp.next;
        }
        temp.next = heroNode;
    }
}
  1. test
public class Test_1_水浒传排行 {
    
    
    public static void main(String[] args) {
    
    
       // 1. 测试
        HeroNode h1 = new HeroNode(1, "A", "a");
        HeroNode h2 = new HeroNode(2, "B", "b");
        HeroNode h3 = new HeroNode(3, "C", "c");
        HeroNode h4 = new HeroNode(4, "D", "d");
        HeroNode h5 = new HeroNode(5, "E", "e");

        SingleLinkedList singleLinkedList = new SingleLinkedList();
        singleLinkedList.add(h1);
        singleLinkedList.add(h2);
        singleLinkedList.add(h3);
        singleLinkedList.add(h4);
        singleLinkedList.add(h5);
        singleLinkedList.list();

    }
}

2) Specify the location to add

analyze:

  1. Find the position of the newly added node, through the auxiliary variable (pointer)
  2. new node next = temp.next
  3. set temp.next = new node
    // 第二种:添加时排序
    public void addByOrder(HeroNode heroNode) {
    
    
        // 头节点不动,仍然通过指针辅助
        // 单链表,所以我们查找的是添加位置的前一个节点
        HeroNode temp = head;
        boolean flag = false; // 标志添加的编号是否存在
        while (true) {
    
    
            if (temp.next == null) {
    
    
                // 到达尾部.直接添加
                break;
            }
            if (temp.next.no > heroNode.no) {
    
    
                // 位置找到 添加到temp上
                break;
            }
            if (temp.next.no == heroNode.no) {
    
    
                flag = true;
                break;
            }

            temp = temp.next;
        }
        if (flag) {
    
    
            System.out.println("准备插入的英雄" + heroNode.no + "已经存在");
            return;
        }
        // 插入链表
        heroNode.next = temp.next;
        temp.next = heroNode;
    }

3) Update the node

 // 修改节点信息
    public void update(HeroNode heroNode) {
    
    
        if (head.next == null) {
    
    
            System.out.println("链表为空");
            return;
        }
        // 找到节点
        // 1. 定义复制节点
        HeroNode temp = head.next;
        // 2. 定义标识 --> 是否找到
        boolean flag = false;
        while (true) {
    
    
            // 链表尾部
            if (temp == null) {
    
    
                break;
            }
            // 找到
            if (temp.no == heroNode.no) {
    
    
                flag = true;
                break;
            }
            temp = temp.next;
        }
        // 找到
        if (flag) {
    
    
            temp.nickName = heroNode.nickName;
            temp.name = heroNode.name;

        } else {
    
    
            System.out.println("未找到数据");
        }

    }

4) Delete the node

    // 删除节点
    public void delete(int delNo){
    
    
        // 1. 定义辅助变量
        HeroNode temp = head;
        // 2. 定义flag
        boolean flag = false;
        while (true){
    
    
            if(temp.next == null){
    
    
                break;
            }
            // 3. 找到删除节点
            if(temp.next.no == delNo){
    
    
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if(flag){
    
    
            temp.next = temp.next.next;
        }else {
    
    
            System.out.println("未找到节点");
        }

    }

3. Single chain surface test questions

1) Find the number of nodes in the singly linked list

    // 获取单链表长度【头节点需要去掉】
    public int getSize() {
    
    
        HeroNode curNode = head.next;
        int count = 0;
        while (curNode != null) {
    
    
            count++;
            curNode = curNode.next;
        }
        return count;
    }

2) Find the last K node in the singly linked list

Ideas:

  1. Accept the head node, and accept an index at the same time
  2. index identifies the last index node
  3. First traverse the linked list from the beginning to the end, get the total length and traverse from the first one of the linked list, traverse (size-index) [10 get the penultimate one, traverse 8 times]
    public HeroNode getLastIndex(int index){
    
    
        if(head.next == null)return null;
        int size = getSize();
        // index 合法性
        if(index <=0 || index > size)return null;
        HeroNode temp = head.next;
        for (int i = 0; i < (size - index); i++) {
    
    
            temp = temp.next;
        }
        return temp;
    }

3) Reversal of single linked list

Ideas:

  1. define a new node
  2. Traverse the nodes, adding each value to the head of a new node
    // 反转当前链表
    public void reverse() {
    
    

        HeroNode reverseHead = new HeroNode(0, null, null);
        // 当前节点
        HeroNode cur = head.next;
        HeroNode next = null;
        // 遍历
        while (true) {
    
    
            if (cur == null) {
    
    
                break;
            }
            next = cur.next;

            // 反转插入
            cur.next = reverseHead.next;
            reverseHead.next = cur;

            // 后移
            cur = next;
        }
        head.next = reverseHead.next;
    }

4) Print the singly linked list in reverse

  // 从尾到头打印链表
    // 利用栈打印
    public void reverseByStack(){
    
    
        Stack<HeroNode> heroStack = new Stack<>();
        HeroNode temp = head.next;
        while (true){
    
    
            if(temp == null){
    
    
                break;
            }
            heroStack.push(temp);
            temp = temp.next;
        }
        while (!heroStack.empty()){
    
    
            System.out.println(heroStack.pop());
        }

    }

5) Merge two ordered singly linked lists

    // 合并两个有序链表
    public void concatTwo(HeroNode a, HeroNode b) {
    
    
        HeroNode tempA = a;
        HeroNode tempB = b.next;
        if (tempA.next == null) {
    
    
            tempA.next = tempB;
            return;
        }
        if (tempB == null) {
    
    
            return;
        }
        while (true) {
    
    
            if (tempA.next == null) {
    
    
                break;
            }
            if (tempB.next == null) {
    
    
                break;
            }
            if (tempA.next.no > tempB.no) {
    
    
                // b 当头
                HeroNode heroNode = new HeroNode(tempB.no, tempB.name, tempB.nickName);
                // a 接后面
                heroNode.next = tempA.next;
                // a 后面变成b 遍历
                tempA.next = heroNode;
                tempB = tempB.next;
            }
            tempA = tempA.next;
        }
        tempA.next = tempB;
        // 给当前链表赋值
        head.next = tempA;
    }
}

4. Application examples of doubly linked list

1 Introduction

Disadvantage analysis of managing singly linked list:

  1. In a singly linked list, the search direction can only be in one direction, while a doubly 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, while the two-way linked list can be deleted by itself, so when we delete the single-linked list, we always find temp, which is the previous node of the node to be deleted

2) case

// 双向链表
class DoubleLinkedList {
    
    

    private HeroNode2 head = new HeroNode2(0, "", "");

    public HeroNode2 getHead() {
    
    
        return head;
    }

    // 添加节点
    public void add(HeroNode2 heroNode) {
    
    
        HeroNode2 temp = head;
        while (temp.next != null) {
    
    
            temp = temp.next;
        }
        temp.next = heroNode;
        heroNode.pre = temp;
    }

    // 顺序添加
    public void addByOrder(HeroNode2 heroNode) {
    
    
        HeroNode2 temp = head;
        boolean flag = false;
        while (true) {
    
    
            if (temp.next == null) {
    
    
                // 尾部
                break;
            }
            if (temp.next.no > heroNode.no) {
    
    
                break;
            }
            if (temp.next.no == heroNode.no) {
    
    
                flag = true;
                break;
            }
            // 后移
            temp = temp.next;
        }
        if (flag) {
    
    
            System.out.println("值:" + heroNode.no + "重复");
            return;
        }
        if (temp.pre == null) {
    
    
            // temp == head
            heroNode.next = temp.next;
            temp.next = heroNode;
            heroNode.pre = head.pre;
        } else {
    
    
            temp.pre.next = heroNode;
            heroNode.pre = temp.pre;
            temp.pre = heroNode;
            heroNode.next = temp;
        }


    }

    // 修改节点
    public void update(HeroNode2 heroNode) {
    
    
        if (heroNode == null) return;
        HeroNode2 temp = head;
        while (temp.next != null) {
    
    
            if (temp.no == heroNode.no) {
    
    
                temp.name = heroNode.name;
                temp.nickName = heroNode.nickName;
                break;
            }
            temp = temp.next;
        }
    }

    // 删除节点
    public void delete(int delNo) {
    
    
        HeroNode2 temp = head;
        boolean flag = false;
        while (temp.next != null) {
    
    
            if (temp.no == delNo) {
    
    
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if (flag) {
    
    
            if (temp.pre != null) {
    
    
                temp.pre.next = temp.next;
            } else {
    
    
                head.next = null;
            }
        }
    }

    // 遍历打印
    public void list() {
    
    
        HeroNode2 temp = head.next;
        while (temp != null) {
    
    
            System.out.println(temp);
            temp = temp.next;
        }
    }

}


class HeroNode2 {
    
    

    public int no;
    public String name;
    public String nickName;
    public HeroNode2 pre;
    public HeroNode2 next;

    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 + '\'' + "}";
    }
}

5. Application of one-way circular linked list

1) Joseph problem

insert image description here
Joseph Baidu Encyclopedia

Josephhu’s problem is: Let n people numbered 1, 2, ... n sit in a circle, agree that the person numbered k (1<=k<=n) will start counting from 1, and the person who counts to m will go out , its next person starts counting from 1, and the person who counts to m goes out of the queue again, and so on, until everyone goes out of the queue, thus generating a sequence of queue numbers.

n = 5, that is, there are 5 people
k = 1, start counting from the first person
m = 2, count 2

The order of out circle
2->4->1->5->3

// Copied, the teacher didn't understand what he said, but I can realize it by myself, see the replay for details



//创建一个环形的单向链表
public class CircleSingleLinkedList {
    
    
    //创建一个first节点 当前没有编号 代表第一个小孩
    private Boy first = new Boy(-1);

    //添加小孩节点,构建成一个环形的链表
    public void addBoy(int nums) {
    
    //nums代表总的小孩个数
        if (nums < 1) {
    
    
            System.out.printf("nums值不正确");
            return;
        }
        //因为first不能动  所以创建一个辅助指针来构建环形链表
        Boy curBoy = null;
        for (int i = 1; i <=nums; i++) {
    
    
            //根据编号创建小孩节点
            Boy boy = new Boy(i);
            //第一个小孩 自己构成环形
            if (i == 1) {
    
    
                first = boy;
                boy.setNext(first);
                curBoy = first;
            } else {
    
    
                curBoy.setNext(boy);
                boy.setNext(first);
                curBoy = boy;
            }
        }

    }

    //显示环形链表
    public void showBoy() {
    
    
        if (first == null) {
    
    
            System.out.println("链表为空,无小孩");
            return;
        }
        //因为first不能动 仍然需要辅助指针
        Boy curBoy = first;
        while (true) {
    
    
            System.out.printf("小孩的编号是:%d\n", curBoy.getNo());
            if (curBoy.getNext() == first) {
    
    
                break;
            }
            curBoy = curBoy.getNext();//curBoy后移
        }
    }

    //根据用户的输入计算出小孩出圈的顺序

    /**
     * @param startNo  表示从第几个小孩开始数数
     * @param countNum 表示数几下
     * @param nums     表示最初有多少小孩
     */
    public void countBoy(int startNo, int countNum, int nums) {
    
    
        if (first == null || startNo < 1 || startNo > nums) {
    
    
            System.out.printf("参数输入有误 请重新输入");
            return;
        }
        //创建辅助指针 帮助小孩出圈
        Boy helper = first;
        //辅助指针应该指向环形链表的最后节点
        while (true) {
    
    
            if (helper.getNext() == first) {
    
    
                break;//说明helper指向最后一个小孩节点
            }
            helper = helper.getNext();
        }
        //小孩报数前,先让first和helper移动k-1次
        for (int i = 0; i < startNo - 1; i++) {
    
    
            first = first.getNext();
            helper = helper.getNext();
        }
        //小孩报数时,让first和helper移动m-1次 然后出圈
        while (true) {
    
    
            if (helper == first) {
    
    
                break;//圈中只剩一个节点
            }
            for (int i = 0; i < countNum - 1; i++) {
    
    
                first = first.getNext();
                helper = helper.getNext();
            }
            //这时first指向的节点就是要出圈的小孩
            System.out.printf("小孩%d出圈\n", first.getNo());
            //将first指向的节点出圈
            first = first.getNext();
            helper.setNext(first);
        }
        System.out.printf("最后留在圈中的小孩编号%d\n", helper.getNo());
    }

}



//创建Boy类 代表一个节点
public class Boy {
    
    
    private int no;
    private Boy next;//指向下一个节点 默认null

    public Boy(int no) {
    
    
        this.no = no;
    }

    public int getNo() {
    
    
        return no;
    }

    public void setNo(int no) {
    
    
        this.no = no;
    }

    public Boy getNext() {
    
    
        return next;
    }

    public void setNext(Boy next) {
    
    
        this.next = next;
    }
}


6. Replay code

1) One-way linked list

Test Methods

  public static void testLinkedList() {
    
    
        LinkedList linkedList = new LinkedList();
        for (int i = 9; i > 1; i--) {
    
    
            Node1 node1 = new Node1(i, String.valueOf(i));

//            linkedList.add(node1);
            linkedList.addByOrder(node1);
        }
        linkedList.list();
        System.out.println("------更新节点------");
        Node1 n1 = new Node1(5, "张飞");
        linkedList.update(n1);
        linkedList.list();
        System.out.println("------删除节点------");
        linkedList.delete(5);
        linkedList.list();
        System.out.println("------获取长度-------");
        System.out.println(linkedList.size());
        System.out.println("------获取倒数第 3 个节点------");
        linkedList.getLastIndex(3);
        System.out.println("-----链表反转-------");
        linkedList.reverse();
        linkedList.list();
        System.out.println("-----反向打印--------");
        linkedList.printReverse();
        System.out.println("-----合并两个链表-----");
        // linkedListA = [2,4,6,8,10]
        // linkedListB = [1,3,5,7,9]
        LinkedList linkedListA = new LinkedList();
        LinkedList linkedListB = new LinkedList();
        Random random = new Random();
        int num = random.nextInt(10);
        for (int i = 2; i < 30; i += num) {
    
    
            linkedListA.addByOrder(new Node1(i, String.valueOf(i)));
        }
        for (int i = 1; i < 30; i += num) {
    
    
            linkedListB.addByOrder(new Node1(i, String.valueOf(i)));
        }
        System.out.println("-----A------");
        linkedListA.list();
        System.out.println("-----B------");
        linkedListB.list();
        System.out.println("----合并------");
        linkedList.concat(linkedListA.head.next, linkedListB.head.next);
        linkedList.list();
    }

Node class

class Node1 {
    
    
    Node1 next;
    int id;
    String name;

    public Node1(int id, String name) {
    
    
        this.id = id;
        this.name = name;
    }

    @Override
    public String toString() {
    
    
        return "Node1{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

LinkedList class

Basic CRUD

class LinkedList {
    
    

    // 链表起始点
    Node1 head = new Node1(0, "");

    // 添加节点
    public void add(Node1 node) {
    
    
        // 1. 验证参数
        if (node == null) {
    
    
            System.out.println("参数 不能为空");
            return;
        }
        // 2. 遍历链表, 加入链表末尾
        // 3. 定义一个辅助指针,帮助遍历
        Node1 temp = head;
        while (temp.next != null) {
    
    
            // 4. 指针后移
            temp = temp.next;
        }
        temp.next = node;
    }

    // 排序添加节点
    public void addByOrder(Node1 node) {
    
    
        // 1. 验证参数
        if (node == null) {
    
    
            System.out.println("参数 不能为空");
            return;
        }
        // 2. 创建临时变量遍历 指向遍历的前一个
        Node1 temp = head;
        // 3. 创建标识标志添加位置
        boolean flag = false;
        // 4. 遍历
        while (temp.next != null) {
    
    
            // 5. 找到添加位置
            if (temp.next.id > node.id) {
    
    
                flag = true;
                break;
            }
            // 6.指针后移
            temp = temp.next;
        }
        // 7. 有位置
        if (flag) {
    
    
            node.next = temp.next;
            temp.next = node;
        } else {
    
    
            // 8. 直接添加到末尾
            temp.next = node;
        }
    }

    // 更新节点
    public void update(Node1 node) {
    
    
        // 1. 验证参数
        if (node == null) {
    
    
            System.out.println("参数 不能为空");
            return;
        }
        // 2. 定义临时变量
        Node1 temp = head.next;
        boolean flag = false;
        while (temp != null) {
    
    
            if (temp.id == node.id) {
    
    
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if (flag) {
    
    
            temp.name = node.name;
        }
    }

    // 删除节点
    public void delete(int id) {
    
    
        if (id > 0) {
    
    
            // 1. 创建辅助变量
            Node1 temp = head;
            boolean flag = false;
            // 2. 遍历
            while (temp.next != null) {
    
    
                if (temp.next.id == id) {
    
    
                    flag = true;
                    break;
                }
                temp = temp.next;
            }
            // 3. 删除数据
            if (flag) {
    
    
                // temp此时为需要删除的节点的上一个
                temp.next = temp.next.next;
            }
        }
    }
    // 遍历打印链表
    public void list() {
    
    
        // 1. 辅助指针
        Node1 temp = head.next;
        // 2. 循环遍历
        while (temp != null) {
    
    
            System.out.println(temp);
            temp = temp.next;
        }
    }
}

Get the number of linked lists

 public int size() {
    
    
        // 1. 定义两个变量
        Node1 temp = head.next;
        int count = 0;
        while (temp != null) {
    
    
            count++;
            temp = temp.next;
        }
        return count;
    }

Find the nth last node

  public void getLastIndex(int lastIndex) {
    
    
        // 1. 创建临时变量
        Node1 temp = head.next;
        // 2. 获取循环长度
        int size = size();
        if (lastIndex > size || lastIndex < 1) {
    
    
            System.out.println("index不合法");
            return;
        }
        for (int i = 0; i < (size - lastIndex); i++) {
    
    
            temp = temp.next;
        }
        System.out.println(temp);
    }

single table inversion

public void reverse() {
    
    
        // 1. 定义临时变量
        Node1 temp = head.next;
        // 2. 定义存储变量
        Node1 next = null;
        Node1 newNode = new Node1(0, "");
        // 3. 循环
        while (temp != null) {
    
    
            // 临时存储剩下循环变量
            next = temp.next;
            // 进行反转
            // 例如 [【2】,3,4,5] = [0,null,]
            temp.next = newNode.next;
            // temp = [2,null]
            // temp = [3,2,null]
            newNode.next = temp;
            // 后移
            temp = next;
        }
        head = newNode;
    }

Reverse print singly linked list, using the concept of stack

 public void printReverse() {
    
    
        // 1. 创建栈
        Stack<Node1> stack = new Stack<>();
        // 2. 循环链表
        Node1 temp = head.next;
        while (temp != null) {
    
    
            stack.push(temp);
            temp = temp.next;
        }
        // 3. 打印stack
        while (!stack.empty()) {
    
    
            System.out.println(stack.pop());
        }
    }

Merge two sorted singly linked lists

 public void concat(Node1 n1, Node1 n2) {
    
    
        // 1. 创建指针
        Node1 tempA = n1;
        Node1 tempB = n2;
        if (tempA == null) {
    
    
            head.next = tempB;
            return;
        }
        if (tempB == null) {
    
    
            head.next = tempA;
            return;
        }
        Node1 newNode = new Node1(0, "");
        // head存储 newNode
        head = newNode;
        // 2. 遍历
        while (true) {
    
    
            if (tempA.next == null) {
    
    
                break;
            }
            if (tempB.next == null) {
    
    
                break;
            }
            if (tempA.id > tempB.id) {
    
    
                // 举例
                // 保证next最后一位指向A
                newNode.next = tempB;
                tempB = tempB.next;
                newNode = newNode.next;
                newNode.next = tempA;
            } else {
    
    
                newNode.next = tempA;
            }
            newNode = newNode.next;
            tempA = tempA.next;
        }
        // 3. 其中一个遍历完毕
        //  拼接B
        newNode.next = tempB;
    }

2) Doubly linked list

Test Methods

    // 双向链表测试
    public static void testTwoLinkedList() {
    
    
        TwoLinkedList linkedList = new TwoLinkedList();
        System.out.println("------添加-------");
        for (int i = 10; i > 0; i--) {
    
    
            Node2 node = new Node2(i, String.valueOf(i));
            linkedList.addByOrder(node);
        }
        linkedList.list();
        System.out.println("------更新-------");
        linkedList.update(new Node2(3, "张飞"));
        linkedList.list();
        System.out.println("------删除-------");
        linkedList.delete(3);
        linkedList.list();
        System.out.println("------添加-------");
        System.out.println("------添加-------");

    }

Node class

// 双向
class Node2 {
    
    
    Node2 pre;
    Node2 next;
    int id;
    String name;

    public Node2(int id, String name) {
    
    
        this.id = id;
        this.name = name;
    }

    @Override
    public String toString() {
    
    
        return "Node1{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

Two-LinkedList class

//
class TwoLinkedList {
    
    

    Node2 head = new Node2(0, "");

    // 添加
    public void add(Node2 node) {
    
    
        // 1. 验证参数
        if (node == null) {
    
    
            System.out.println("参数 不能为空");
            return;
        }
        // 2. 临时变量
        Node2 temp = head;
        // 3. 遍历
        while (temp.next != null) {
    
    
            temp = temp.next;
        }
        // 赋值
        temp.next = node;
        node.pre = temp;

    }

    // 修改
    public void update(Node2 node) {
    
    
        // 1. 验证参数
        if (node == null) {
    
    
            System.out.println("参数 不能为空");
            return;
        }
        Node2 temp = head.next;
        while (temp != null) {
    
    
            if (temp.id == node.id) {
    
    
                temp.name = node.name;
                return;
            }
            temp = temp.next;
        }
        throw new RuntimeException("该节点不存在");

    }

    // 删除
    public void delete(int id) {
    
    
        Node2 temp = head.next;
        while (temp != null) {
    
    
            if (temp.id == id) {
    
    
                temp.pre.next = temp.next;
                return;
            }
            temp = temp.next;
        }
        throw new RuntimeException("该节点不存在");

    }

    // 遍历
    public void list() {
    
    
        Node2 temp = head.next;
        while (temp != null) {
    
    
            System.out.println(temp);
            temp = temp.next;
        }
    }

    // 顺序添加
    public void addByOrder(Node2 node){
    
    
        // 1. 验证参数
        if (node == null) {
    
    
            System.out.println("参数 不能为空");
            return;
        }
        Node2 temp  = head;
        boolean flag = false;
        while (temp.next != null){
    
    
            if(temp.next.id > node.id){
    
    
                flag = true;
                break;
            }
            temp = temp.next;
        }if(flag){
    
    
               node.next = temp.next;
                temp.next = node;
                node.pre = temp;
        }else {
    
    
            temp.next = node;
            node.pre = temp;
        }
    }

}

3) One-way circular linked list

Test Methods

 public static void testCycleLinkedList() {
    
    
        CycleLinkedList cycleLinkedList = new CycleLinkedList();
        for (int i = 1; i <= 5; i++) {
    
    
            cycleLinkedList.add(new Node1(i, String.valueOf(i)));
        }
        System.out.println("---添加-----");
        cycleLinkedList.list();
        System.out.println("---约瑟夫问题-----");
        cycleLinkedList.Joseph(1, 2);
        System.out.println("-----2---------");
//        cycleLinkedList.calcJosephuOrder(2,5);
    }
   

Joseph method

class CycleLinkedList {
    
    
    public Node1 head;


    // 添加
    public void add(Node1 node) {
    
    
        Node1 temp = head;
        if (temp == null) {
    
    
            head = node;
            node.next = head;
            return;
        }
        while (temp.next.id != head.id) {
    
    
            temp = temp.next;
        }
        temp.next = node;
        node.next = head;
    }

    // 遍历
    public int list() {
    
    
        int count = 0;
        Node1 temp = head;
        if (temp == null) {
    
    
            return 0;
        }
        while (temp.next.id != head.id) {
    
    
            temp = temp.next;
//            System.out.println(temp);
            count++;
        }
        return count;
    }

    // 约瑟夫问题
    public void Joseph(int k, int m) {
    
    
        // k = 第几个小孩的id
        // m = 数几次
        // 1. 这里不验证参数了, 直接省略 head.id = 0
        Node1 temp = head;
        int size = list();
        while (size > 0) {
    
    
            if (temp.id == k) {
    
    
                for (int i = 0; i < m - 2; i++) {
    
    
                    temp = temp.next;
                }
                // temp 为要删除的 前一个
                System.out.println(temp.next);
                temp.next = temp.next.next;
                k = temp.next.id;
                size--;
            }
            temp = temp.next;
        }
        System.out.println(temp);

    }

}

Guess you like

Origin blog.csdn.net/m0_56186460/article/details/124225133