链表LikedKist(单向链表、双向链表、单向循环链表)

二、链表(Linked List)

链表是以节点(node)存储的链式存储结构,一个node包含一个data域(存放数据)和一个next域(存放下一个node的指针),链表的各个节点不一定是连续的,它可以分为带头结点和不带头结点。头结点仅包含next域。

1、单向链表

1.1顺序插入

  • 创建节点类,包含了data和next,next指向下一个节点对象

    class PersonNode {
    public int number;
    public String name;
    public String nickName;
    public PersonNode next;
    
    public PersonNode(int number, String name, String nickName) {
      this.number = number;
      this.name = name;
      this.nickName = nickName;
    }
    
    @Override
    public String toString() {
      return "PersonNode{" +
              "number=" + number +
              ", name='" + name + '\'' +
              ", nickName='" + nickName + '\'' +
              '}';
    }
    }
    
  • 创建单向链表类,里面包含了增删改查的方法

  • 在链表类创建head Node,头节点的next指向第一个节点

  • 实现增删改查的方法
    在这里插入图片描述

  • 在链表中增加一个节点

确定要插入的节点位置,循环遍历到该位置节点的上一个节点。

S->next=P->next
P->next=S
  • 在链表中删除一个节点

确定删除的位置,循环遍历到该位置节点的上一个节点

P->next=p->next->next
  • 遍历链表

     PersonNode temp = headNode;
            while (true) {
                if (temp.next == null) {
                    break;
                }
                temp = temp.next;
                System.out.println(temp);
            }
    
  • 修改链表中的一个节点信息

确定要修改节点的位置,先遍历找到该节点,修改该节点的信息。

2、双向链表

双向链表是在单向链表的基础上加入pre指针,因此支持双向的增删改查。

	public int number;
public String name;
public String nickName;
public PersonNode next;
public PersonNode pre;
  • 双向链表的遍历

双向链表的遍历与单向链表相同,可以按照两个方向遍历。

  • 双向链表的添加

1、在末尾添加
在这里插入图片描述

在双向链表的末尾添加C节点(定位到节点B)

B->next=C
C->pre=B

2、在两节点间添加
在这里插入图片描述

在节点B和节点C间添加D(程序定位到节点D),

顺序:先搞定D的前驱和后继节点,再搞定C的节点的前驱和B的后继节点。

D->pre=B
D->next=C
C->pre=D
B->next=D
  • 双向链表的修改

同单链表修改相同

  • 双向链表的删除

1、在链表尾部删除(定位到节点P(B))
在这里插入图片描述
2、在两节点间删除(定位到节点S(D))
在这里插入图片描述

3、单向循环链表(无头结点)

单向循环链表是首尾相连,使整个单链表构成一个环。约瑟夫问题时单向循环链表的一个典型的应用

约瑟夫问题描述:

约瑟夫问题是一个非常著名的趣题,即由n个人坐成一圈,按顺时针由1开始给他们编号。* 然后由第一个人开始报数,数到m的人出局。现在需要求的是最后一个出局的人的编号。* 给定两个int n和m,代表游戏的人数。请返回最后一个出局的人的编号.

问题分析:

约瑟夫问题可以简单分为两个步骤

构造Boy节点类

 private int number;
 private Boy next;
  • 构建一个单向循环链表
    在这里插入图片描述

定义两个指针变量First和cur,first表示头结点,cur指向当前节点

构造第一个节点first
first = boy;//第一个节点为first
first.setNext(first);//仅有一个节点时,first指向first,构成闭环
cur = first;//辅助变量指向first
构造其它节点 
cur.setNext(boy);//将新添加的节点设置为当前节点的后继节点
boy.setNext(first);//新添加的节点与first构成闭环
cur=boy;//将当前节点设置为新添加的节点
  • 根据约定的规则退出循环链表,直至仅有一个节点
    在这里插入图片描述

定义两个辅助节点变量first和helper,first指向每一轮要开始的节点,helper指向最后一个节点,当first与helper指向同一个节点时,该循环链表仅剩一个节点

构造函数
moveCycle(int no,int number,int sum)
1、确定从第几个节点开始
for(int i=0;i<no-1;i++){
      first=first.getNext();
      helper=helper.getNext();
  }
2、循环,找出节点,直至仅剩一个节点
while (true){
      if(first==helper){
          System.out.printf("最后一个节点时%d\n",first.getNumber());
          break;
      }
      //开始,每number下,出圈一次
      for(int j=0;j<number-1;j++){
          first=first.getNext();
          helper=helper.getNext();
      }
      System.out.printf("%d出圈\n",first.getNumber());
      first=first.getNext();
      helper.setNext(first);
  }
发布了71 篇原创文章 · 获赞 42 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/dreame_life/article/details/104118898