JAVA data structure and algorithm (3) linked list

Recently I learned about linked lists, and wrote something for later review. The linked lists are mainly introduced from the following aspects (1) Why use linked lists (2) Introduction to linked lists (3) Logic analysis and code implementation of singly linked lists (4) Two-way Linked list logic analysis and code implementation (5) Analysis of common interview questions of singly linked list (6) Joseph ring realization (7) Summary.

(1) Why use a linked list

     Arrays and linked lists are the most basic linear data structures, which can be used to implement non-linear stacks, queues and other data structures with specific application scenarios. Array is a very useful data structure provided by programming languages, but it has two flaws. (1) If you want to change the size of the array, you need to create a new array and copy the data in the original array to the new array (2 ) The memory of the array data is stored sequentially, which means that to add new data to the array, you need to move other data. In other words, searching in an unordered array is inefficient, and inserting in an ordered array is inefficient. In either case, the efficiency of deletion is very low; and once the array is created, the size cannot be changed. These defects can be overcome by linked lists. The chain structure is a collection of nodes that store data and chain pointers to other nodes. In this way, nodes can be located anywhere in the memory, and from one node to another in the chain structure. The transfer of a node can be realized by storing references between nodes in the structure. The most flexible way to realize the chain structure is to use an independent object for each node.

(2) Introduction to Linked List

           You can think of a linked list as an ordered list. A linked list is a common basic data structure. It is a linear list. As the name implies, it is a linked list of data nodes. Each node consists of two parts: data And the pointer to the next node, a storage unit with one data field and multiple pointer fields is usually called a node.

é¾è¡¨ç»æå¾

  • The first node and the last node of the linked list are called the head node and the end node of the linked list, respectively. The characteristic of the tail node is that its next reference is null. The next reference of each node in the linked list is equivalent to a pointer to another node. With these next references, we can move from the head node to the end node of the linked list.

The structure of the linked list is shown in the figure below,

è¿éåå¾çæè¿ °

Linked lists are usually divided into singly linked lists, doubly linked lists, circular linked lists and so on.

The advantages and disadvantages of linked lists are:

The advantages of linked lists are:

  1. Using the linked list structure can overcome the disadvantage that the data size of the array linked list needs to be known in advance. The linked list structure can make full use of the computer memory space and realize flexible dynamic memory management. 
  2. The physical storage unit is not continuous, and dynamic memory allocation is adopted, which can effectively allocate and utilize memory resources; 
  3. Node deletion and insertion are simple, and no reorganization of memory space is required. 

The disadvantages of linked lists are: 

  1. Index access is not possible, only searching sequentially from the head node; 
  2. The data structure is more complex, requires a lot of pointer operations, and is prone to errors.
  3. The linked list loses the advantage of random reading of the array, and at the same time the linked list has a relatively large space overhead due to the increase of the pointer field of the node.

to sum up:

The linked list is stored in the form of nodes. Each node contains the data field in the chain storage. The next field: points to the next node. As shown in the figure: It is found that each node of the linked list is not necessarily stored continuously. The linked list is divided into the linked list of the lead node and no The linked list of the head node is determined according to actual needs.

(3) Logic analysis and code realization of singly linked list

        If a node contains a data field that points to another node, then multiple nodes can be connected in series, and only one node can be accessed through one variable. Such a sequence of nodes is a linked list whose data structure is composed of nodes, and each node saves the original The data information of the node and the reference to the next node. If a node only contains references to its successor nodes, the linked list becomes a singly linked list.

The singly linked list with the head node is shown in the figure:

The storage structure of a singly linked list:

Single linked list implementation case:

Use a singly linked list with head to achieve-Water Margin Heroes Leaderboard Management

  1. Complete the operation of adding, deleting, modifying, and checking heroes. Note: Delete, modify, search
  2. The first method adds directly to the end of the linked list when adding heroes
  3. In the second way, when adding a hero, insert the hero into the specified position according to the ranking

Analysis of singly linked list logic implementation:

In the singly linked list, the operation is added:

To implement the delete operation in the singly linked list:

Traversal of singly linked list:

Modification of singly linked list:

The code implementation of the Water Margin Hero Gang of the singly linked list:

package JAVADATASTRTUCRE;
/**
 * Created with IntelliJ IDEA.
 * User:  yongping Li
 * Date: 2020/11/18
 * Time: 23:51
 * Description: No Description
 */
public class SingleLinkedListDemo {
    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(hero4);
//        singleLinkedList.add(hero2);
//        singleLinkedList.add(hero3);
        //添加按照编号
        singleLinkedList.addByOrder(hero1);
        singleLinkedList.addByOrder(hero4);
        singleLinkedList.addByOrder(hero2);
        singleLinkedList.addByOrder(hero3);
//修改显示
//        HeroNode heroNode = new HeroNode(1, "宋江", "投降派");
//        singleLinkedList.update(heroNode);
//        singleLinkedList.list();
        singleLinkedList.list();
        System.out.println("****************************************");
    singleLinkedList.delete(1);
    singleLinkedList.delete(2);
    singleLinkedList.delete(3);
    singleLinkedList.delete(4);

        //遍历
        //singleLinkedList.list();
    }
}

//定义单链表
//定义singleLinkedList,管理我们的英雄
class SingleLinkedList{
    //先定义头节点
    private HeroNode head=new HeroNode(0,"","");
  //添加节点到单链表
    public void add(HeroNode heroNode){
         HeroNode temp =head;
         while(true){
             //链表的最后
             if(temp.next==null){
                 break;
             }
             temp=temp.next;
         }
      //退出循环时,temp指向链表的最后
         temp.next=heroNode;
    }
    //依顺序添加
    public void addByOrder(HeroNode heroNode){

        HeroNode temp =head;
        boolean 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){//编号存在
            flag=true;
            break;
        }
        temp=temp.next;//后移,遍历当前链表
        }

        //判断flag;
        if(flag){
            System.out.println("待添加的英雄已经存在,其编号为:"+heroNode.no);
        }else{//添加数据到temp的后面
            heroNode.next=temp.next;
            temp.next=heroNode;
        }
    }

    //修改节点的信息
    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.println("没有找到编号为"+newHeroNode.no+"的英雄");
        }
    }
     //删除节点
      public void delete(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.println("节点不存在");
         }
        }
      }
    //遍历
    public  void list(){
        //判断链表是否为空
        if(head.next==null){
            System.out.println("链表为空");
            return;
        }
        HeroNode temp=head.next;
        while(true){
            if(temp==null){
                break;
            }
            //打印节点、
            System.out.println(temp);
            //temp后移
            temp=temp.next;
        }
    }
}


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

    public HeroNode(int hNo,String hName,String hNickName){
            this.no=hNo;
            this.name=hName;
            this.nickName=hNickName;
    }
    public String toString(){
        return "heroNode [ no="+no+", name=" + name + ", nickname="+nickName+"]";
    }

}

The results of the operation are:

heroNode [ no=1, name=宋江, nickname=及时雨]
heroNode [ no=2, name=卢俊义, nickname=玉麒麟]
heroNode [ no=3, name=吴用, nickname=智多星]
heroNode [ no=4, name=林冲, nickname=豹子头]
#######################################
heroNode [ no=1, name=宋江, nickname=投降派]
heroNode [ no=2, name=卢俊义, nickname=玉麒麟]
heroNode [ no=3, name=吴用, nickname=智多星]
heroNode [ no=4, name=林冲, nickname=豹子头]
****************************************
节点不存在
heroNode [ no=1, name=宋江, nickname=投降派]
heroNode [ no=2, name=卢俊义, nickname=玉麒麟]
heroNode [ no=3, name=吴用, nickname=智多星]
heroNode [ no=4, name=林冲, nickname=豹子头]

Process finished with exit code 0

Realization of singly linked list two

package DataStrtureDemo;

/**
 * Created with IntelliJ IDEA.
 * User:  yongping Li
 * Date: 2020/11/19
 * Time: 21:11
 * Description: No Description
 */
public class IntSLListDemo {
    public static void main(String[] args) {

        IntSLList intSLList = new IntSLList();
        intSLList.addToHead(1);
        intSLList.addToHead(2);
        intSLList.addToHead(3);
        intSLList.addToHead(4);
        intSLList.addToHead(5);
        //打印所有
        intSLList.printAll();

       //判断是否包含某个元素
        System.out.println(intSLList.isInList(5));
    }

}

 class IntSLListNode{
     public int info;
     public IntSLListNode next;
     public IntSLListNode(int i){
         this(i,null);
     }
     public IntSLListNode(int i,IntSLListNode node){
         info=i;
         next=node;
     }
}
class  IntSLList{
    protected IntSLListNode head,tail;
    public IntSLList(){
        head=tail=null;
    }
    public boolean isEmpty(){
        return  head==null;
    }

    public void addToHead(int el){
       head=new IntSLListNode(el,head);
       if(tail==null){
           tail=head;
       }
    }

    public void addToTail(int el){

        if(!isEmpty()){//单链表不为空
            tail.next=new IntSLListNode(el);
            tail=tail.next;
        }else {//单链表为空时
            head=tail=new IntSLListNode(el);
        }
    }
//删除头节点
    public int deleteFromHead(){
        int el=head.info;
        if(head ==tail){
            head=tail=null;
        }else{
            head=head.next;
        }
        return el;
    }
    //删除尾节点
    public int deleteFromTail(){
         int el=tail.info;
         if(head==tail){
             head=tail=null;
         }else{
           IntSLListNode  tmp;
           for(tmp=head;tmp.next!=tail;tmp=tmp.next);
           tail=tmp;
           tail.next=null;
         }
         return el;
    }
    //打印单链表
    public void printAll(){
         for(IntSLListNode tmp =head;tmp!=null;tmp=tmp.next){
             System.out.println(tmp.info+"");
         }
    }
    //判断是否在单链表中
    public boolean isInList(int el){
     IntSLListNode tmp;
     for(tmp=head;tmp!=null&&tmp.info!=el;tmp=tmp.next);
     return tmp!=null;
    }
    //删除某个节点
    public void delete(int el){
        if(!isEmpty()){
        if(head==tail&& el==head.info){
         head=tail=null;
        }else if(el==head.info){
            head=head.next;
        }else{
            IntSLListNode pred,tmp;
            for(pred=head,tmp=head.next;tmp!=null&&tmp.info != el;pred=pred.next,tmp=tmp.next){
                if(tmp!=null){
                    pred.next=tmp.next;
                }
                if(tmp==tail){
                    tail=pred;
                }
            }
          }
        }
    }

}

The results of the operation are:

(4) Logical analysis and code realization of doubly linked list

Use a doubly linked list with head to achieve-analysis of the disadvantages of the Water Margin hero ranking list management singly linked list:

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

A singly linked list cannot be deleted by itself and needs to rely on auxiliary nodes, while a doubly linked list can be deleted by itself, so when we delete the singly linked list, the node always finds temp, which is the previous node of the node to be deleted,

Single necklace table, if we want to add a node at the tail, we must traverse from the head to the tail, find the tail node, and then insert a node after the tail node. This operation is very troublesome,

If you redefine the linked list so that one node has two reference domains, one points to the predecessor node and the other points to the successor node, such a linked list is a doubly linked list.

Logical analysis of the realization of doubly linked list:

Implementation of deletion

Code implementation of doubly linked list:

package JAVADATASTRTUCRE;

/**
 * Created with IntelliJ IDEA.
 * User:  yongping Li
 * Date: 2020/11/19
 * Time: 4:17
 * Description: No Description
 */
public class doubleLinkedListDemo {
    public static void main(String[] args) {
        System.out.println("双向链表的测试");
        HeroNode2 hero1 = new HeroNode2(1, "宋江", "及时雨");
        HeroNode2 hero2 = new HeroNode2(2, "卢俊义", "玉麒麟");
        HeroNode2 hero3 = new HeroNode2(3, "吴用", "智多星");
        HeroNode2 hero4 = new HeroNode2(4, "林冲", "豹子头");
        //创建双向链表对象
        DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
        doubleLinkedList.add(hero1);
        doubleLinkedList.add(hero2);
        doubleLinkedList.add(hero3);
        doubleLinkedList.add(hero4);


        doubleLinkedList.list();
        System.out.println("**********");
        HeroNode2 heroNode2 = new HeroNode2(2, "公胜", "入龙");
        doubleLinkedList.update(heroNode2);
       // doubleLinkedList.delete(3);
        doubleLinkedList.list();

    }
}

//创建双向链表的类
class DoubleLinkedList{
    //初始化
    private HeroNode2 head=new HeroNode2(0,"","");
    //返回头节点
    public HeroNode2 getHead(){
        return head;
    }

    public void add(HeroNode2 heroNode){
        HeroNode2 temp =head;
        while(true){
            //链表的最后
            if(temp.next==null){
                break;
            }
            temp=temp.next;
        }
        //退出循环时,temp指向链表的最后,
        //形成一个双向链表
        temp.next=heroNode;
        heroNode.pre=temp;
    }

    //删除一个节点
    //删除节点,双向链表,直接找到删除节点,自我删除
    public void delete(int no){

        if(head.next==null){
            System.out.println("链表为空,无法删除");
        }

        HeroNode2 temp=head.next;
        boolean flag=false;//标志是否找到删除节点
        while(true){
            if(temp==null){//已经找到链表最后节点的next
                break;
            }
            if(temp.no==no){//找到待删除节点的前一个节点的temp
                flag=true;
                break;
            }
            temp=temp.next;
            if(flag){//删除节点
                temp.pre.next=temp.next;
                //注意:最后一个节点不能执行下面这句话,否则
                //出现空指针异常
                if(temp.next!=null) {
                    temp.next.pre = temp.pre;
                }
            }else{
                System.out.println("节点不存在");
            }
        }

    }


//修改一个结点的内容
//修改节点的信息
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.println("没有找到编号为"+newHeroNode.no+"的英雄");
    }

  }

    //遍历
    public  void list(){
        //判断链表是否为空
        if(head.next==null){
            System.out.println("链表为空");
            return;
        }
        HeroNode2 temp=head.next;
        while(true){
            if(temp==null){
                break;
            }
            //打印节点、
            System.out.println(temp);
            //temp后移
            temp=temp.next;
        }
    }
}

//定义节点,每个HeroNode对象都是一个节点
class HeroNode2{
    public int no;
    public String name;
    public String nickName;
    public HeroNode2 next;//指向下一个节点,默认为null
   public HeroNode2 pre;//指向前一个节点,默认为null
    public HeroNode2(int hNo,String hName,String hNickName){
        this.no=hNo;
        this.name=hName;
        this.nickName=hNickName;

    }
    public String toString(){
        return "heroNode [ no="+no+", name=" + name + ", nickname="+nickName+"]";
    }
}

The results of the operation are:

(5) Common interview questions for singly linked lists

Common interview questions for singly linked lists are as follows:

  1. Find the number of valid nodes in the singly linked list Find the kth node from the bottom in the singly linked list
  2. Reversal of singly linked list
  3. Print the singly linked list from the end to the beginning [Required Method 1: Reverse traversal. Method 2: Stack Stack]

2. Reversal logic analysis of singly linked list

3. Logical analysis of printing singly linked lists in reverse order 

package JAVADATASTRTUCRE;

import java.util.Stack;

/**
 * Created with IntelliJ IDEA.
 * User:  yongping Li
 * Date: 2020/11/19
 * Time: 1:44
 * Description: No Description
 */
 class testSingleLinkedListDemo {
    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, "林冲", "豹子头");
        testSingleLinkedList testSingleLinkedList = new testSingleLinkedList();
        //添加
        //singleLinkedList.add(hero1);
        //singleLinkedList.add(hero4);
        //singleLinkedList.add(hero2);
        //singleLinkedList.add(hero3);
        //添加按照编号
         testSingleLinkedList.addByOrder(hero1);
         testSingleLinkedList.addByOrder(hero4);
         testSingleLinkedList.addByOrder(hero2);
        testSingleLinkedList.addByOrder(hero3);
//修改显示
//        HeroNode heroNode = new HeroNode(1, "宋江", "投降派");
//        singleLinkedList.update(heroNode);
//        singleLinkedList.list();
         testSingleLinkedList.list();
        System.out.println("****************************************");
//        singleLinkedList.delete(1);
//        singleLinkedList.delete(2);
//        singleLinkedList.delete(3);
//        singleLinkedList.delete(4);
        //遍历
        //singleLinkedList.list();
        // System.out.println(getLength(testSingleLinkedList.getHead()));
        HeroNode res =finalLastIndexNode(testSingleLinkedList.getHead(),2);
       System.out.println("res="+res);

     //单链表的反转
        System.out.println("反转单链表");
        reverselist(testSingleLinkedList.getHead());
        testSingleLinkedList.list();

        System.out.println("***********************");
         reversePrint(testSingleLinkedList.getHead());


    }

    //获取单链表有效节点的个数(若带头节点,不需要统计)
    /*
    @param head 链表头节点
    @return 返回的是有效节点的个数
     */

    public static int getLength(HeroNode head) {
        if (head.next == null) {
            return 0;
        }
        int length = 0;
        HeroNode cru = head.next;
        while (cru != null) {
            length++;
            cru = cru.next;
        }
        return length;
    }

   //查找单链表倒数第k各节点
     public static HeroNode finalLastIndexNode(HeroNode head,int index){
        if(head.next==null){
            return null;
        }
        int size=getLength(head);
        if(index<=0||index>size){
            return null;
        }
        HeroNode   cru=head.next;

         for (int i=0;i<size-index;i++){
           cru=cru.next;
         }
         return cru;



     }

    //单链表反转
     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;




    }

    //利用栈来逆序打印单链表

    public static void reversePrint(HeroNode head){
        if(head.next==null){
            return;//空链表,无法打印
        }
        Stack<HeroNode> heroNodestack = new Stack<HeroNode>();
        HeroNode cur=head.next;
        while (cur!=null){
            heroNodestack.push(cur);
            cur=cur.next;//cur后移,指向写一个节点
        }

        //将栈中的数据打印
        while (heroNodestack.size()>0){
            System.out.println(heroNodestack.pop());
        }

    }



}

//定义单链表
//定义singleLinkedList,管理我们的英雄
class testSingleLinkedList{
    //先定义头节点
    private HeroNode head=new HeroNode(0,"","");
  //返回头节点
    public HeroNode getHead(){
        return head;
    }
    //添加节点到单链表
    public void add(HeroNode heroNode){
        HeroNode temp =head;
        while(true){
            //链表的最后
            if(temp.next==null){
                break;
            }
            temp=temp.next;
        }
        //退出循环时,temp指向链表的最后
        temp.next=heroNode;
    }
    //依顺序添加
    public void addByOrder(HeroNode heroNode){

        HeroNode temp =head;
        boolean 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){//编号存在
                flag=true;
                break;
            }
            temp=temp.next;//后移,遍历当前链表
        }

        //判断flag;
        if(flag){
            System.out.println("待添加的英雄已经存在,其编号为:"+heroNode.no);
        }else{//添加数据到temp的后面
            heroNode.next=temp.next;
            temp.next=heroNode;
        }
    }

    //修改节点的信息
    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.println("没有找到编号为"+newHeroNode.no+"的英雄");
        }

    }
    //删除节点
    public void delete(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.println("节点不存在");
            }
        }

    }
    //遍历
    public  void list(){
        //判断链表是否为空
        if(head.next==null){
            System.out.println("链表为空");
            return;
        }
        HeroNode temp=head.next;
        while(true){
            if(temp==null){
                break;
            }
            //打印节点、
            System.out.println(temp);
            //temp后移
            temp=temp.next;
        }
    }
}


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

    public testHeroNode(int hNo,String hName,String hNickName){
        this.no=hNo;
        this.name=hName;
        this.nickName=hNickName;
    }
    public String toString(){
        return "heroNode [ no="+no+", name=" + name + ", nickname="+nickName+"]";
    }

}

The results of the operation are:

 

(6) The realization of Joseph ring

Problem Description:

Josephu (Joseph, Joseph ring) question Josephu question is:

Suppose n people with numbers 1, 2, ... n sit in a circle, and it is agreed that the person with number k (1<=k<=n) starts counting from 1, and the person who counts to m goes out of the queue. A person starts counting from 1 again, and the person who counts to m goes out again, and so on, until everyone goes out, which produces a sequence of dequeue numbers.

Tip: Use a circular linked list without a leading node to deal with Josephu's problem: first form a single circular linked list with n nodes, and then count from 1 from node k. When m is counted, the corresponding node starts from the linked list. Delete from the list, and then count from 1 again from the next node of the deleted node, until the last node is deleted from the linked list and the algorithm ends.

logical analysis:

Josephu's question is:

Suppose n people with numbers 1, 2, ... n sit in a circle, and it is agreed that the person with number k (1<=k<=n) starts counting from 1, and the person who counts to m goes out of the queue. A person starts counting from 1 again, and the person who counts to m goes out again, and so on, until everyone goes out, which produces a sequence of dequeue numbers.

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

The idea of ​​constructing a one-way circular linked list

  1.  Create the first node first, let first point to the node, and form a ring
  2. When we create a new node later, we can add the node to the existing circular linked list.

Traverse the circular list

  1. Let an auxiliary pointer (variable) curBoy first point to the first node
  2.  Then traverse the circular linked list through a while loop to end curBoy.next == first

Code:

package JAVADATASTRTUCRE;


/**
 * Created with IntelliJ IDEA.
 * User:  yongping Li
 * Date: 2020/11/19
 * Time: 15:01
 * Description: No Description
 */
public class Jusepfu {
    public static void main(String[] args) {
        CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
        circleSingleLinkedList.addBoy(5);
        circleSingleLinkedList.showBoy();
        System.out.println("******************************");
     //测试出圈
        circleSingleLinkedList.countBoy(1,2,5);

    }
    
}

//创建环形单项链表
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 (int i = 1; i < nums+1; i++) {
            //根据编号创建小孩节点
            Boy boy = new Boy(i);
            //第一个小孩
            if (i == 1) {
                first = boy;
                first.setNext(first);
                curBoy = first;
            } else {
                curBoy.setNext(boy);
                boy.setNext(first);
                curBoy = boy;
            }
        }
    }
     ///遍历所有节点
       public void showBoy(){
           if(first==null){//链表为空
               System.out.println("没有数据");
               return;
           }
           Boy curBoy=first;
           while (true){
               System.out.println("小孩的编号为"+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.println("参数输入有误,请重新输入");
            return;
        }
        //辅助变量
        Boy helper=first;
      //需要创建辅助变量,事先指向环形链表的最后一个节点
      while (true){
          if(helper.getNext()==first){//helper指向最后
              break;
          }
          helper=helper.getNext();
      }
      //小孩报数前,first和helper移动k-1次
      for(int j=0;j<startNO-1;j++){
         first=first.getNext();
         helper=helper.getNext();
      }
     //小孩移动时,helper和first同时移动m-1次,然后出圈
      while (true){
          if (helper==first){//圈中只有一个人
              break;
          }

      //让first和helper同时移动countnum-1
        for(int j=0;j<countNum-1;j++){
            first=first.getNext();
            helper=helper.getNext();
        }
       //此时first指向出圈小孩
        System.out.println("小孩出圈id为"+first.getNo());
        first=first.getNext();
        helper.setNext(first);
    }
      System.out.println("最后在圈内的小孩的编号为"+first.getNo());
    }
}



//创建一个boy类,表示一个节点
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;
}
}

The results of the operation are:


小孩的编号为1
小孩的编号为2
小孩的编号为3
小孩的编号为4
小孩的编号为5
******************************
小孩出圈id为2
小孩出圈id为4
小孩出圈id为1
小孩出圈id为5
最后在圈内的小孩的编号为3

Process finished with exit code 0

(7) Summary

      Compared with the array, the linked list adds the position of the next node, including the predecessor node and the successor node. Each linked list includes aLinikedList object and many Node objects. Only the reference of the next node is called a singly linked list, and both have It is called a doubly linked list. If the next value is null, it means that it is the end of the linked list. If we want to find a node, we must traverse from the first node and continue to find the next node through next until we find what we need.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Guess you like

Origin blog.csdn.net/weixin_41792162/article/details/109911000
Recommended