[java]-算法与数据结构-第四章-链表

四、链表

1. 介绍

链表是有序的列表, 但是它在内存中是存储如下

在这里插入图片描述

  1. 链表是以节点的方式来存储,是链式存储
  2. 每个节点包含 data 域, next 域: 指向下一个节点.
  3. 如图: 发现链表的各个节点不一定是连续存储
  4. 链表分带头节点的链表和没有头节点的链表, 根据实际的需求来确定

单链表(带头结点)逻辑结构图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xKf3sdi9-1649340941711)(https://secure2.wostatic.cn/static/uPyAcsmSPWx5wPBJSQjFDJ/image.png)]

2. 单链表的应用实例

使用带 head 头的单向链表实现 – 水浒英雄排行榜管理完成对英雄人物的增删改查操作

1)添加链表尾部

分析:
先创建一个Head头结点,作用就是表示单链表的头
后面每次添加节点,就是加入到链表的最后的位置。

  1. 定义HeroNode
@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. 定义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. 测试
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)指定位置添加

分析:

  1. 找到新添加的节点的位置,通过辅助变量(指针)
  2. 新的节点 next = temp.next
  3. 将temp.next = 新的节点
    // 第二种:添加时排序
    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)更新节点

 // 修改节点信息
    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)删除节点

    // 删除节点
    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. 单链表面试题

1)求单链表中节点的个数

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

2)查找单链表中的倒数第K个节点

思路:

  1. 接受head节点, 同时接受一个index
  2. index标识倒数第 index个节点
  3. 先把链表从头到尾遍历, 获取总长度 从链表的第一个开始遍历,遍历 (size-index)个【10个获取倒数第二个,遍历8次】
    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)单链表的反转

思路:

  1. 定义一个新节点
  2. 遍历节点,每个值添加到新节点头部
    // 反转当前链表
    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)反向打印单链表

  // 从尾到头打印链表
    // 利用栈打印
    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)合并两个有序的单链表

    // 合并两个有序链表
    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. 双向链表的应用实例

1) 介绍

管理单向链表的缺点分析:

  1. 单向链表, 查找的方向只能是一个方向, 而双向链表可以向前或者向后查找。
  2. 单向链表不能自我删除, 需要靠辅助节点 , 而双向链表, 则可以自我删除, 所以前面我们单链表删除时节点, 总是找到 temp,temp 是待删除节点的前一个节点

2)案例

// 双向链表
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. 单向环形链表的应用

1)约瑟夫问题

在这里插入图片描述
约瑟夫 百度百科

Josephu 问题为:设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。

n = 5 , 即有5个人
k = 1, 从第一个人开始报数
m = 2, 数2下

出圈的顺序
2->4->1->5->3

// 复制的,老师讲的没听懂,不过自己能实现出来,具体看复盘



//创建一个环形的单向链表
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. 复盘代码

1)单向链表

测试方法

  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 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 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;
        }
    }
}

获取链表个数

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

查找倒数第 n 个节点

  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);
    }

单表反转

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;
    }

反向打印单链表,利用栈的概念

 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());
        }
    }

合并两个有序单链表

 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)双向链表

测试方法

    // 双向链表测试
    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 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 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)单向循环链表

测试方法

 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);
    }
   

约瑟夫方法

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);

    }

}

猜你喜欢

转载自blog.csdn.net/m0_56186460/article/details/124225133
今日推荐