[java algorithm] sparse array/queue/single and double linked list

Linear and Nonlinear Structures

insert image description here

sparse array

foreword

Introduction
insert image description here
Introduction to sparse arrays
insert image description here
insert image description here
The idea of ​​converting two-dimensional arrays and sparse arrays
insert image description here

the code

Two-dimensional array to sparse array

public class SparseArray {
    
    
    public static void main(String[] args) {
    
    
        //创建一个原始的二维数组 11*11
        //0:表示没用棋子 1:表示黑子 2:表示蓝子
        int chessArr1[][] = new int[11][11];
        chessArr1[1][2] = 1;
        chessArr1[2][4] = 2;
        chessArr1[4][3] = 1;

        //输出原始的二维数组
        System.out.println("原始的二维数组:");
        //#1.java中的双循环特殊写法 --把下面的双循环更换看看效果--一样的
        for(int[] row : chessArr1){
    
    
            for (int data:row){
    
    
                System.out.printf("%d\t",data);
            }
            System.out.println();
        }
        //将二维数组 转为 稀疏数组
        //1.先遍历二维数组得到非0数据个数
        int sum = 0;
        for (int i = 0;i<11;i++){
    
    
            for (int j = 0;j<11;j++){
    
    
                if (chessArr1[i][j] != 0){
    
    
                    sum++;
                }
            }
        }
//        //新双循环版本
//        for (int[] row : chessArr1){
    
    
//            for (int data:row){
    
    
//                if (data != 0){
    
    
//                    sum++;
//                }
//            }
//        }
        System.out.println("sum = "+sum);

        //2.创建对应的稀疏数组
        int sparseArr[][] = new int[sum + 1][3];
        //给稀疏数组赋值
        sparseArr[0][0] = 11;
        sparseArr[0][1] = 11;
        sparseArr[0][2] = sum;
        //遍历二维数组,将非0的值存放到sparseArr中
        int count = 0;//用于记录是第几个非0的数据
        for (int i = 0; i < 11; i++) {
    
    
            for (int j = 0; j < 11; j++) {
    
    
                if (chessArr1[i][j] != 0){
    
    
                    count++;
                    sparseArr[count][0] = i;
                    sparseArr[count][1] = j;
                    sparseArr[count][2] = chessArr1[i][j];
                }
            }
        }

        //输出稀疏数组的形式
        System.out.println();
        System.out.println("得到稀疏数组为:");
        //#2.多维数组的length是行吗?
        for (int i = 0; i < sparseArr.length; i++) {
    
    
            //#3.只有printf可以处理类似%d的转义字符
            System.out.printf("%d\t%d\t%d\t\n",sparseArr[i][0],sparseArr[i][1],sparseArr[i][2]);
        }
        System.out.println();
    }
}

Convert sparse array to two-dimensional array

System.out.println("=================================");

        //稀疏数组转为二维数组
        //1.先读取稀疏数组的第一行,工具第一行的数据,创建原始的二维数组
        int chessArr2[][] = new int[sparseArr[0][0]][sparseArr[0][1]];


        //2.在读取稀疏数组后几行的数据(从第二行开始),并赋值 原始的二维数组
        for (int i = 1; i < sparseArr.length; i++) {
    
    
            chessArr2[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
        }

        //输出恢复后的二维数组
        System.out.println();
        System.out.println("恢复后的二维数组");

        for (int[] row : chessArr2){
    
    
            for (int data : row){
    
    
                System.out.printf("%d\t",data);
            }
            System.out.println();
        }

insert image description here

brush type questions

[Title]
Sparse array search. Given a sorted array of strings interspersed with empty strings, write a method to find the position of a given string.
[Example 1]
Input: words = ["at", "", "", "", "ball", "", "", "car", "", "", "dad", "", " "], s = "ta"
output: -1
description: does not exist return -1
[Example 2]
input: words = ["at", "", "", "", "ball", "", "" , "car", "", "", "dad", "", ""], s = "ball"
Output: 4
[Hint]
The length of words is between [1, 1000000]

Idea
Idea
1. Convert one-dimensional character array to sparse array
Sparse array composition:
num sum
13 1
pos ch
4 ball
2. Use ball to traverse to find sparse array
3. Find the value of output sparsearray[i][0]

Questions:
1. I don’t understand how to input empty elements by
myself. 2. Pay attention to how the count is written

A quick solution to this question
JAVA Exercise 195-Sparse Array Search

package sparseArrayDemo;

import java.util.Scanner;

public class T1 {
    
    
    public static void main(String[] args) {
    
    
        //创建一个一维字符数组
        String words[] = new String[13];
        //给原数组赋值
        words[0] = "at";
        words[4] = "ball";
        words[7] = "car";
        words[10] = "dad";

        //输入s的值
        Scanner scanner = new Scanner(System.in);
        String s = scanner.next();

        //转换为稀疏数组

        //获取sum值
        int sum = 0;
        for (int i = 0; i < words.length; i++) {
    
    
            //# 数组中空元素的表示
            if (words[i] != null){
    
    
                sum++;
            }
        }
        String sparseArr[][] = new String[sum+1][2];
        //给稀疏数组赋值
        //# toString的效率最高
        sparseArr[0][0] = Integer.toString(words.length);
        sparseArr[0][1] = Integer.toString(sum);

        int count = 0;
        for (int i = 0; i < words.length; i++) {
    
    
            if (words[i] != null){
    
    
                count++;
                sparseArr[count][0] = Integer.toString(i);
                sparseArr[count][1] = words[i];
            }
        }

        //输出稀疏数组 ok
//        for (int i = 0; i < sum+1; i++) {
    
    
//            for (int j = 0; j < 2; j++) {
    
    
//                //# %s表示
//                System.out.printf("%s\t",sparseArr[i][j]);;
//            }
//            System.out.println();
//        }

        //查找输入的s的位置
        boolean flag = false;
        for (int i = 1; i < sum; i++) {
    
    
            if (sparseArr[i][1].equals(s)){
    
    
                System.out.println(sparseArr[i][0]);
                flag = true;
            }
        }
        if (flag == false){
    
    
            System.out.println(-1);
        }
    }
}

insert image description here

queue

non-circular queue

The concept of queue
insert image description here
Array simulation queue
insert image description hereArray simulation queue – deposit analysis
insert image description here
Demonstration program:

package ArrayQueueDemo;

import java.util.Scanner;

public class queueDY {
    
    
    public static void main(String[] args) {
    
    
        //创建一个队列
        ArrayQueue queue = new ArrayQueue(3);
        char key = ' '; //接收用户输入
        Scanner scanner = new Scanner(System.in);
        boolean loop = true;    //构造菜单循环

        //输出菜单
        while (loop){
    
    
            System.out.println("s(show):显示队列");
            System.out.println("e(exit):退出程序");
            System.out.println("a(add):添加数据到队列");
            System.out.println("g(get):从队列取出数据");
            System.out.println("h(head):查看队列头的数据");

            key = scanner.next().charAt(0); //接收一个字符
            switch (key){
    
    
                case 's':
                    queue.showQueue();
                    break;
                case 'a':
                    System.out.println("输入一个数");
                    int value = scanner.nextInt();
                    queue.addQueue(value);
                    break;
                case 'g':
                    try{
    
    
                        int res = queue.getQueue();
                        System.out.printf("取出的数据是%d\n",res);
                    }catch (Exception e){
    
    
                        //TODO:handle exception
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h':
                    try{
    
    
                        int res = queue.headQueue();
                        System.out.printf("取出的数据是%d\n",res);
                    }catch (Exception e){
    
    
                        //TODO:handle exception
                        System.out.println(e.getMessage());
                    }
                case 'e':
                    //#
                    scanner.close();
                    loop = false;
                    break;
                default:
                    break;
            }
        }
        System.out.println("程序退出!");
    }

}
//使用数组模拟队列--编写一个ArrayQueue类
class ArrayQueue{
    
    
    private int maxSize;    //表示数组的最大容器
    private int front;         //队列头
    private int rear;       //队列尾
    private int[] arr;      //该数组用于存放数据,mono队列

    //创建队列的构造器
    public ArrayQueue(int arrMaxSize){
    
    
        maxSize = arrMaxSize;
        arr = new int[maxSize];
        front = -1; //指向队列的头部,(front是指向队列头的前一个位置)
        rear = -1;  //指向队列尾,(指向队列的最后一个数据)
    }

    //判断队列是否满
    public boolean isFull(){
    
    
        return rear == maxSize - 1;
    }

    //判断队列是否为空
    public boolean isEmpty(){
    
    
        return rear == front;
    }

    //添加数据到队列
    public void addQueue(int n){
    
    
        //判断队列是否满
        if (isFull()){
    
    
            System.out.println("队列满,不能加入到队列");
            return;
        }
        rear++; //让rear后移
        arr[rear] = n;
    }

    //获取队列的数据,出队列
    public int getQueue(){
    
    
        //判断队列是否空
        if (isEmpty()){
    
    
            //通过抛出异常
            throw new RuntimeException("队列空,不能取数据");
        }
        front++;    //front后移
        return arr[front];
    }

    //显示队列的所有数据
    public void showQueue(){
    
    
        //遍历
        if (isEmpty()){
    
    
            System.out.println("队列空,不能加入到队列!");
            return;
        }

        for (int i = 0; i < arr.length; i++) {
    
    
            System.out.printf("arr[%d]=%d\n",i,arr[i]);
        }
    }

    //显示队列的头数据,注意不是取出数据
    public int headQueue(){
    
    
        //判断
        if (isEmpty()){
    
    
            throw new RuntimeException("队列空,不能取数据");
        }
        return arr[front+1];
    }
}

Bugs:
1. i starts from 0 in showQueue(), so you can’t check the data even
if you fetch it. You can only use headQueue to check the situation. In ++, it will definitely exceed
because the array needs to be moduloed to form a ring queue

ring queue

insert image description here
the code

1 showQueue changed to i from front, to solve bug1
2 Modulo changed to ring queue, to solve bug2

package ArrayQueueDemo;

import java.util.Scanner;

public class CircleArrayQueue {
    
    
    public static void main(String[] args) {
    
    
        //创建一个队列
        //此时多了一个月定位置,所以需要+1
        CircleArray queue = new CircleArray(4);
        char key = ' '; //接收用户输入
        Scanner scanner = new Scanner(System.in);
        boolean loop = true;    //构造菜单循环

        //输出菜单
        while (loop){
    
    
            System.out.println("s(show):显示队列");
            System.out.println("e(exit):退出程序");
            System.out.println("a(add):添加数据到队列");
            System.out.println("g(get):从队列取出数据");
            System.out.println("h(head):查看队列头的数据");

            key = scanner.next().charAt(0); //接收一个字符
            switch (key){
    
    
                case 's':
                    queue.showQueue();
                    break;
                case 'a':
                    System.out.println("输入一个数");
                    int value = scanner.nextInt();
                    queue.addQueue(value);
                    break;
                case 'g':
                    try{
    
    
                        int res = queue.getQueue();
                        System.out.printf("取出的数据是%d\n",res);
                    }catch (Exception e){
    
    
                        //TODO:handle exception
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h':
                    try{
    
    
                        int res = queue.headQueue();
                        System.out.printf("队列的头数据是:%d\n",res);
                    }catch (Exception e){
    
    
                        //TODO:handle exception
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e':
                    //#
                    scanner.close();
                    loop = false;
                    break;
                default:
                    break;
            }
        }
        System.out.println("程序退出!");
    }


}
class CircleArray{
    
    
    private int maxSize;        //表示数组的最大容器
    private int front;          //队列头
    private int rear;           //队列尾
    private int[] arr;          //该数组用于存放数据,mono队列

    public CircleArray(int arrMaxSize){
    
    
        maxSize = arrMaxSize;
        arr = new int[maxSize];
        front = 0;
        rear = 0;
        //front和rear默认值为0,所以也可以不写
    }

    //判断队列是否满
    public boolean isFull(){
    
    
        return (rear + 1) % maxSize == front;
    }

    //判断队列是否为空
    public boolean isEmpty(){
    
    
        return rear == front;
    }

    //添加数据到队列
    public void addQueue(int n){
    
    
        //判断队列是否满
        if (isFull()){
    
    
            System.out.println("队列满,不能加入到队列");
            return;
        }
        //直接将数据加入
        arr[rear] = n;
        //将rear后移,这里必须考虑取膜
        rear = (rear + 1) % maxSize;
    }

    //获取队列的数据,出队列
    public int getQueue(){
    
    
        //判断队列是否空
        if (isEmpty()){
    
    
            //通过抛出异常
            throw new RuntimeException("队列空,不能取数据");
        }
        int value = arr[front];
        front = (front + 1) % maxSize;
        return value;
    }

    //球当前队列的有效数据个数
    public int size(){
    
    
        return (rear + maxSize - front) % maxSize;
    }

    //显示队列的所有数据
    public void showQueue(){
    
    
        //遍历
        if (isEmpty()){
    
    
            System.out.println("队列空,没有数据!");
            return;
        }
        //i从front开始,因为
        for (int i = front; i < front+size(); i++) {
    
    
            System.out.printf("arr[%d]=%d\n",i % maxSize,arr[i % maxSize]);
        }
    }

    //显示队列的头数据,注意不是取出数据
    public int headQueue(){
    
    
        //判断
        if (isEmpty()){
    
    
            throw new RuntimeException("队列空,不能取数据");
        }
        return arr[front];
    }
}

brush questions

I didn't see the question about the queue

Single list

Definition of singly linked list

insert image description here
insert image description here

Case Demo – Code

insert image description here
the code

1. Add in order

package linkedlist;

public class SingleLinkedListD3emo {
    
    
    public static void main(String[] args) {
    
    
        //进行测试
        //先创建节点
        HeroNode hero1 = new HeroNode(1,"宋江","及时雨");
        HeroNode hero2 = new HeroNode(2,"卢俊义","玉麒麟");
        HeroNode hero3 = new HeroNode(3,"吴用","智多星");
        HeroNode hero4 = new HeroNode(4,"林冲","豹子头");

        //创建链表
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        //加入操作
//        singleLinkedList.add(hero1);
//        singleLinkedList.add(hero2);
//        singleLinkedList.add(hero3);
//        singleLinkedList.add(hero4);
        singleLinkedList.add(hero1);
        singleLinkedList.add(hero3);
        singleLinkedList.add(hero4);
        singleLinkedList.add(hero2);

        //显示操作
        singleLinkedList.list();

    }
}

//定义SingleLinkedList 管理我们的英雄
class SingleLinkedList{
    
    
    //先初始化一个头结点,头节点不动不存放数据(因为头结点用来定位的)
    private HeroNode head = new HeroNode(0,"","");

    //添加节点到单链表
    //思路:按照顺序添加
    // 1.找到当前链表的最后节点 2.将最后这个节点等等next指向新节点
    public void add(HeroNode heroNode){
    
    
        //因为head不能动,所以我们需要一个辅助遍历temp
        HeroNode temp = head;
        //遍历链表找到最后
        while (true){
    
    
            //找到链表的最后
            if (temp.next == null){
    
    
                break;
            }
            //如果没有找到最后,将temp后移
            temp = temp.next;
        }
        //当退出while循环时,temp就指向了链表的最后
        temp.next = heroNode;
    }

    //显示链表
    public void list(){
    
    
        //判断链表是否为空
        if (head.next == null){
    
    
            System.out.println("链表为空");
            return;
        }
        //引入辅助变量temp
        HeroNode temp = head.next;
        while (true){
    
    
            //判断是否到链表最后
            if (temp == null){
    
    
                break;
            }
            //输出节点的信息
            System.out.println(temp);
            //将temp后移
            temp = temp.next;
        }
    }


}

//定义HeroNode,每个HeroNode对象就是一个节点
class HeroNode{
    
    
    public int no;
    public String name;
    public String nickname;
    public HeroNode next;   //指向下一个节点

    //构造器

    public HeroNode(int no, String name, String nickname) {
    
    
        this.no = no;
        this.name = name;
        this.nickname = nickname;
    }
    //为了显示方法,重新toString

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

Requirements: add in order
insert image description here

2. Insert by hero rank

Linked list insertion
insert image description here
code:
(add method addByOrder in SingleLinkedList class)

//第二种添加方式:按排名添加
    public void addByOrder(HeroNode heroNode){
    
    
        //因为头节点不能动,因此我们需要一个辅助指针temp
        //因为是单链表,所以我们找的temo是位于添加位置前一个节点,否则插入失败
        HeroNode temp = head;
        boolean flag = false;   //flag标准添加的编号是否存在,默认为false
        while (true){
    
    
            if (temp.next == null){
    
    //说明temp已经到链表的最后了
                break;
            }
            if (temp.next.no > heroNode.no){
    
    //位置找到,就在temp后面插入
                break;
            }else if (temp.next.no == heroNode.no){
    
    //说明希望添加的heroNode的标号已经存在
                flag = true;//说明标号存在
                break;
            }
            temp = temp.next;
        }
        if (flag){
    
    
            //说明编号存在
            System.out.printf("准备插入的英雄的编号%d已经存在了,不能加入\n",heroNode.no);
        }else {
    
    
            //插入到链表中(temp的后面)
            heroNode.next = temp.next;
            temp.next = heroNode;
        }
    }

Regardless of insertion order, the output remains ordered:
insert image description here

3. Modify the node information according to the no number

Code: (add method in SingleLinkedList class)

//修改节点的信息,根据no编号来修改(no本身不能改
    //1.根据newHeroNode 的 no 来修改即可
    public void upDate(HeroNode newHeroNode){
    
    
        //判断是否为空
        if (head.next == null){
    
    
            System.out.println("链表为空!");
            return;
        }
        //找到需要修改的节点
        HeroNode temp = head.next;
        boolean flag = false;
        while (true){
    
    
            if (temp == null){
    
    
                break; //已经遍历完链表
            }
            if (temp.no == newHeroNode.no){
    
    
                //找到
                flag = true;
                break;
            }
            temp = temp.next;
        }
        //根据flag 判断是否找到要修改的节点
        if (flag){
    
    
            temp.name = newHeroNode.name;
            temp.nickname = newHeroNode.nickname;
        }else {
    
    //没找到
            System.out.printf("没找到编号%d的节点,不能修改\n",newHeroNode.no);
        }
    }

insert image description here

4. Delete node

insert image description hereIn the SingleLinkedList class

//删除节点
    public void del(int no){
    
    
        HeroNode temp = head;
        boolean flag = false;
        while (true){
    
    
            if (temp.next == null){
    
    
                //已经到链表的最后
                break;
            }
            if (temp.next.no == no){
    
    
                //找到的待删除节点的前一个节点temp
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if (flag){
    
    
            //找到
            temp.next = temp.next.next;
        }else {
    
    
            System.out.printf("要删除的%d节点不存在\n",no);
        }
    }

in the main method

//删除一个节点
        singleLinkedList.del(1);
        singleLinkedList.del(4);
        singleLinkedList.del(2);
        singleLinkedList.del(3);
        System.out.println("删除后链表的情况:");

show:
insert image description here

Singly linked list brushing questions

insert image description here

1. Find the number of valid nodes in the singly linked list

In the main class, but set the method outside main:

    //获取单链表中有效节点的个数
    public static int getLength(HeroNode head){
    
    
        if (head.next == null){
    
    //空链表
            return  0;
        }
        int length = 0;
        //定义一个辅助变量
        HeroNode cur = head.next;
        while (cur != null){
    
    //遍历
            length++;
            cur = cur.next;
        }
        return length;
    }

Inside main:

        System.out.println("有效的节点个数:"+getLength(singleLinkedList.getHead()));//4

insert image description here

2. Find the penultimate k-th node in the singly linked list

own version:

//查找单链表中的倒数第k个节点
    public static void getReK(int len,int k,HeroNode head){
    
    
        //转变为正数下的顺序数
        int no = len - k + 1;

        //去找no序号,并输出其信息
        HeroNode temp = head;
        boolean flag = false;
        while (true){
    
    
            if (temp.next == null){
    
    
                //已经走到最后都没找到
                break;
            }
            if (temp.next.no == no){
    
    
                //找到no序号,去输出其信息
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if (flag){
    
    
            //找到
            //输出节点的信息
            System.out.println(temp.next);

        }else {
    
    
            System.out.printf("单链表中的不存在倒数第%d个节点!",k);
        }
    }
System.out.println("去查找单链表中的倒数第k个节点,k==");
        int k = scanner.nextInt();
        getReK(len,k,singleLinkedList.getHead());

Teacher version:

Advantages:
1. Call each other inside the method
2. Declare the method type as HeroNode

//老师版
    //index: 倒数第K
    public static HeroNode findLastIndexNode(HeroNode head,int index){
    
    
        //如果链表为空
        if (head.next == null)
                return null;
        //得到链表的长度
        int size = getLength(head);
        //正数第K个节点的位置:size - index
        //先做一个index检验
        if (index <= 0 || index > size){
    
    
            return null;
        }
        HeroNode cur = head.next;
        for (int i = 0;i<size - index;i++){
    
    
            cur = cur.next;
        }
        return cur;
    }
HeroNode res = findLastIndexNode(singleLinkedList.getHead(),1);
        System.out.println("res="+res);

3. Inversion of singly linked list

Idea:
insert image description here
Code: (teacher version)
In the main method:

System.out.println("反转单链表:");
        reverseList(singleLinkedList.getHead());
        singleLinkedList.list();

Inside the main class outside the main method:

//将单链表反转
    public static void reverseList(HeroNode head){
    
    
        //如果当前链表为空,或者只有一个节点,则无需反转
        if (head.next == null || head.next.next == null){
    
    
            return;
        }

        HeroNode cur = head.next;
        HeroNode next = null; //指向当前节点[cur]的下一个节点(没有记录下个节点,会导致链表记录断开,因为这是单链表)
        HeroNode reverseHead = new HeroNode(0,"","");
        //遍历原来的链表,没遍历一个节点,就取出放在新链表reverseHead的最前端
        while (cur != null){
    
    
            next = cur.next;    //先暂时保存当前节点的下一个节点
            //完整的连接操作
            cur.next = reverseHead.next;//将cur的下一个节点指向链表的最前端
            reverseHead.next = cur;

            cur = next;//让cur后移
        }
        //将head.next指向reverseHead.next,实现反转的最后一步
        head.next = reverseHead.next;
    }

show:
insert image description here

4. Print the singly linked list from end to end [Method 1: Reverse traversal. Method 2: Stack]

insert image description here

//可以利用栈这个数据结构,将各个节点压入栈中,
    // 然后利用栈的先进后出的特点,就实现了逆序打印的效果
    public static void reversePrint(HeroNode head){
    
    
        if (head.next == null){
    
    
            return;//空链表不打印
        }
        //创建要给一个栈,将各个节点压入栈中
        Stack<HeroNode> stack = new Stack<HeroNode>();
        HeroNode cur =head.next;
        //将链表的所有节点压入栈中
        while (cur != null){
    
    
            stack.push(cur);
            cur = cur.next;//cur后移,这样就可以压入下一个节点
        }
        //将栈中的节点进行打印 pop出栈
        while (stack.size() > 0){
    
    
            System.out.println(stack.pop()); //stack特点是先进后出
        }
    }

in main

//方式2:打印反转的单链表
        System.out.println("逆序打印单链表,但没有改变链表的结构:");
        reversePrint(singleLinkedList.getHead());

show:
insert image description here

5. Merge two ordered singly linked lists, the linked list after merging is still in order

insert image description here

[Four classic examples of single linked list (must know)]

Linked list intersection problem

(1) Determine whether the two linked lists intersect?
(2) If they intersect, find the intersecting node.

Thought:
insert image description here
Answer:

Java to determine whether two linked lists intersect

Determine whether there is a palindrome in the linked list

Java judges whether a singly linked list is a palindrome linked list


Doubly linked list

Ideas:
insert image description here

The establishment of two-way linked table:

//创建一个双线链表的类
class DoubleLinkedList{
    
    
    //先初始化一个头节点,头节点不动,不存放
    private HeroNode2 head = new HeroNode2(0,"","");

    public HeroNode2 getHead() {
    
    
        return head;
    }

    //删除双向链表节点
    public void del(int no){
    
    

        //判断当前链表是否为空
        if (head.next == null){
    
    
            System.out.println("链表空,无法删除!");
            return;
        }
        HeroNode2 temp = head.next;
        boolean flag = false;
        while (true){
    
    
            if (temp.next == null){
    
    
                //已经到链表的最后
                break;
            }
            if (temp.no == no){
    
    
                //找到的待删除节点的前一个节点temp
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if (flag){
    
    
            //找到
//            temp.next = temp.next.next;
            temp.pre.next = temp.next;
            //如果是最后一个节点,就不需要执行下面这句话,否则出现空指针
            if (temp.next != null){
    
    
                temp.next.pre = temp.pre;
            }
        }else {
    
    
            System.out.printf("要删除的%d节点不存在\n",no);
        }
    }

    //修改的操作和单向链表一样
    //只是节点类型改为HeroNode2
    public void upDate(HeroNode2 newHeroNode){
    
    
        //判断是否为空
        if (head.next == null){
    
    
            System.out.println("链表为空!");
            return;
        }
        //找到需要修改的节点
        HeroNode2 temp = head.next;
        boolean flag = false;
        while (true){
    
    
            if (temp == null){
    
    
                break; //已经遍历完链表
            }
            if (temp.no == newHeroNode.no){
    
    
                //找到
                flag = true;
                break;
            }
            temp = temp.next;
        }
        //根据flag 判断是否找到要修改的节点
        if (flag){
    
    
            temp.name = newHeroNode.name;
            temp.nickname = newHeroNode.nickname;
        }else {
    
    //没找到
            System.out.printf("没找到编号%d的节点,不能修改\n",newHeroNode.no);
        }
    }

    public void add(HeroNode2 heroNode){
    
    
        //输出和使用temp的时候都有变.next,所以不用修改为head.next
        HeroNode2 temp = head;
        while (true){
    
    
            if (temp.next == null){
    
    
                break;
            }
            temp = temp.next;
        }
        //此时temp指向链表的最后
        //形成一个双向链表
        temp.next = heroNode;
        heroNode.pre = temp;
    }

    //显示链表,遍历方法同单向链表
    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;//指向下一个节点 默认为null
    public HeroNode2 pre;//指向下一个节点 默认为null

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

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

Modify the doubly linked list:

//先创建节点
        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();

insert image description here

Delete doubly linked list:

//删除
        doubleLinkedList.del(3);
        System.out.println("删除链表的情况:");
        doubleLinkedList.list();

insert image description here

Quiz – Add by Rank

Own code:
Outside main:

//按照编号顺序添加
    public static void addByOdser(HeroNode2 heroNode,HeroNode2 head){
    
    
        HeroNode2 temp = head;
        boolean flag = false;   //flag标准添加的编号是否存在,默认为false
        while (true){
    
    
            if (temp.next == null){
    
    //说明temp已经到链表的最后了
                break;
            }
            if (temp.next.no > heroNode.no){
    
    //位置找到,就在temp后面插入
                break;
            }else if (temp.next.no == heroNode.no){
    
    //说明希望添加的heroNode的标号已经存在
                flag = true;//说明标号存在
                break;
            }
            temp = temp.next;
        }
        if (flag){
    
    
            //说明编号存在
            System.out.printf("准备插入的英雄的编号%d已经存在了,不能加入\n",heroNode.no);
        }else {
    
    
            //插入到链表中(temp的后面)
            heroNode.pre = temp;
            temp.next = heroNode;
        }
    }

in main:

//按编号no排序添加
        addByOdser(hero1,doubleLinkedList.getHead());
        addByOdser(hero2,doubleLinkedList.getHead());
        addByOdser(hero3,doubleLinkedList.getHead());
        addByOdser(hero4,doubleLinkedList.getHead());

output:
insert image description here


Found the problem: the reason why the statement is different when the one-way linked list add and addByOder are added
insert image description here
insert image description here
The problem is similar to that in the doubly linked list, where del handles the deletion of the last node
insert image description here

Summary:
Always pay attention to whether the next node is an empty node when the node is in the last position

one-way circular linked list

introduce

insert image description here

Application Scenario – Joseph Problem

insert image description here
insert image description here

Code

Create a one-way circular linked list & add a circular single linked list

  • train of thought

Note:
boy: not a pointer, but a node object
curboy: a pointer

insert image description here
insert image description here
insert image description here
insert image description here

  • the code
package linkedlist;

public class Josepfu {
    
    
    public static void main(String[] args) {
    
    
        //测试-构建 环形链表 和 遍历输出
        CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
        circleSingleLinkedList.addBoy(10);
        circleSingleLinkedList.showBoy();
    }
}
//创建一个环形单向链表
class CircleSingleLinkedList {
    
    
    //创建一个first急待你,当前没有编号(相当于赋初值,后面才给它确切的值
    private Boy first = new Boy(-1);

    //添加小孩节点,构建一个环形链表
    public void addBoy(int nums) {
    
    
        //nums做一个 数据检验
        if (nums < 1) {
    
    
            System.out.println("nums值不正确");
            return;
        }
        Boy curBoy = null;  //辅助指针,帮助构建
        //使用for来创建我们的环形链表
        //???为啥单向链表不能用for来创建
        for (int i = 1; i <= nums; i++) {
    
    
            //根据编号 创建小孩节点
            Boy boy = new Boy(i);
            //如果是第一个小孩
            if (i == 1) {
    
    
                first = boy;
                first.setNext(first);//构成环
                curBoy = first; //让curBoy指向第一个小孩
            } else {
    
    
                //一般添加节点操作
                curBoy.setNext(boy);
                boy.setNext(first);
                curBoy = boy;
            }
        }
    }

    //遍历当前环形链表
    public void showBoy() {
    
    
        //判断链表是否为空
        if (first == null) {
    
    
            System.out.println("没有任何小孩!");
            return;
        }
        //因为first不能动,所以仍然需要一个curBoy完成遍历
        Boy curBoy = first;
        while (true) {
    
    
            System.out.printf("小孩的编号 %d \n", curBoy.getNo());
            if (curBoy.getNext() == first) {
    
    //说明已经遍历完成
                break;
            }
            curBoy = curBoy.getNext();//curBoy后移
        }
    }
}
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;
    }
}

output
insert image description here

Circle out of circular singly linked list

insert image description here
Method in CircleSingleLinkedList:

//出圈小孩节点
    public void countBoy(int startNo,int countNum,int nums){
    
    
        //先对数据进行检验
        if (first == null || startNo < 1 || startNo > nums){
    
    
            System.out.println("参数输入有误,请重新输入");
            return;
        }
        //创建辅助指针
        Boy helper = first;
        //helper指针应该事先,指向环形链表的最后节点
        while (true){
    
    
            if (helper.getNext() == first){
    
    
                break;
            }
            helper = helper.getNext();
        }
        //小孩报数前,先让first和helper移动k - 1次
        for (int j = 0;j < startNo - 1;j++){
    
    
            first = first.getNext();
            helper = helper.getNext();
        }

        //当小孩报数时,让first和helper指针同时移动m - 1次,然后出圈
        //way:喜欢操作,直到全栈只有一个节点
        while (true){
    
    
            if (helper == first){
    
    
                //说明圈中只有一个节点
                break;
            }
            //让first和helper指针同时移动countNum - 1(m - 1)
            for (int i = 0; i < countNum - 1; i++) {
    
    
                first = first.getNext();
                helper = helper.getNext();
            }
            //这时forst指向的节点就是,要出圈的小孩节点
            System.out.printf("小孩%d出圈\n",first.getNo());
            //将first指向的节点出圈
            first = first.getNext();
            //???这样不就forst和helper指向同一个节点了? --理解错误
            //这是一整套完整的出圈操作  等价于:helper.next = first(还是不懂就去看图)
            helper.setNext(first);
        }
        System.out.printf("最后留在全栈的小孩编号%d\n",first.getNo());
    }

in main:

//测试-小孩出圈是否正常
        circleSingleLinkedList.countBoy(1,2,5);

insert image description here

brush questions

2288 Blue Bridge Cup 2018 Ninth Real Question Joseph Ring

insert image description here
Own code: (correct
main

//刷题1
    public static int getLatNo(int k,int n,Boy first){
    
    
        int lastNo;//最后一个剩下的人编号
        //让helper指针应实现走,指向环形链表的最后节点
        Boy helper = first;
        while (true){
    
    
            if (helper.getNext() == first){
    
    
                break;
            }
            helper = helper.getNext();
        }

        //开始报数,让forst和helper同时移动k - 1,然后出圈
        while (true){
    
    
            if (helper == first){
    
    
                //说明圈中只剩下一个节点
                break;
            }
            //开始移动m - 1
            for (int i = 0; i < k - 1; i++) {
    
    
                first = first.getNext();
                helper = helper.getNext();
            }
            //让forst指向的节点出圈
            first = first.getNext();
            helper.setNext(first);
        }
        lastNo = first.getNo();
        return lastNo;
    }

little knowledge

The replaceAll method in the String class: public String replaceAll(String regex, String replacement)
insert image description here

Special writing method of double loop in java

for(int[] row : chessArr1){
    
    
   for (int data:row){
    
    
        System.out.printf("%d\t",data);
    }
    System.out.println();
}

The length of the multidimensional array is the number of rows
sparseArr.length

Only printf can handle escape characters like %d

System.out.printf("%d\t%d\t%d\t\n",sparseArr[i][0],sparseArr[i][1],sparseArr[i][2]);

Guess you like

Origin blog.csdn.net/m0_65431212/article/details/128561989