链表 - Part II

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了链表 - Part II相关的知识,希望对你有一定的参考价值。

循环链表

相比单链表,循环链表将最后一个结点的指针指向了头结点。

循环链表里没有空指针,所以在判断结束条件时不是判断指针是否为空,而是判断指针是否等于某固定指针。

单链表里,一个结点只能访问它后面的结点,但是循环链表里它能访问所有结点。

  技术分享

 

双向链表

指针域记录了结点的上一个结点(前驱结点)和下一个节点(后继节点),这样既可以从头结点遍历到尾结点,也可以从尾结点遍历到头结点。

 技术分享

 

 

约瑟夫问题:

约瑟夫问题来源于犹太历史学家约瑟夫,他和他的一位朋友与另外三十九名犹太人为了躲避罗马人藏在了一个山洞中,三十九位犹太人决定宁愿自杀也不能被抓到。他们商议围成一个圈,从某一个人开始数 ,每数到第 3 的人必须自杀然后再从他之后的人继续数。这时候,约瑟夫把朋友和自己安排在了第 16 和 31 的位置,最终,当其它三十九名犹太人都自杀之后,他们两个躲过一劫。

约瑟夫问题可以用循环链表来模拟。删除操作实现方法如下:

  1. 定义一个遍历指针,初始指向 head,并让 head 指向空地址避免操作结束后变为野指针。
  2. 找到遍历指针往后数的第 n 次所指向的结点。
  3. 输出该结点的数据,更新遍历指针,然后删除该结点。
  4. 重复操作 2 直至只剩下最后一个结点。
  5. 输出最后一个结点并删除。

 

相比之前的单链表类,要实现循环链表类,需要修改其中一些操作。

首先是修改析构函数:

可以将循环链表拆成单链表,其中,让head指向空指针,让它做为链表中的最后一个结点。

 1 ~LinkedList() {
 2         if (head == NULL) {
 3             return;
 4         }
 5         Node<Type> *current_node = head -> next;
 6         head -> next = NULL;
 7         while (current_node != NULL) {
 8             Node<Type> *delete_node = current_node;
 9             current_node = current_node->next;
10             delete delete_node;
11         }
12     }

然后修改插入函数。

 1 void insert(Node<Type> *node, int index) {
 2 // 当head为空时,让node直接赋值给头结点,同时让它指向自己
 3         if (head == NULL) {
 4             if (index != 0) {
 5                 return;
 6             }
 7             head = node;
 8             head -> next = head;
 9             return;
10         }
11 // 当index为0,结点要成为第一个结点时,结点首先指向头结点的下一个结点,然后头结点的下一位再指向结点。 
12 // 注意!!,在循环链表中,head其实该视为尾结点,head -> next才该被视为头结点
13         if (index == 0) {
14             node -> next = head -> next;
15             head -> next = node;
16             return;
17         }
18         Node<Type> * current_node = head -> next;
19         int count = 0;
20 // 寻找目标位置的前一个节点,并且如果遍历到最后一个结点(即head)立刻结束循环
21         while (current_node  != head && count < index - 1) {
22             current_node = current_node->next;
23             count++;
24         }
25         if (count == index - 1) {
26             node->next = current_node->next;
27             current_node->next = node;
28         }
29 // 如果结点插入后成了最后一个结点:(head) -> (node) -> (head -> next),则让它成为head
30         if (node == head -> next) {
31             head = node;
32         }
33     }

接下来实现依次输出被约瑟夫环删除的元素直到只剩最后一个元素的函数

 1 output_josephus()
 2 void output_josephus(int m) {
 3     Node<Type> * current_node = head;
 4     head = NULL;// head指向一个空地址,因为方法执行完后链表将成为空链表,要防止head成为野指针
 5     while (current_node -> next != current_node) {
 6         for (int i = 1; i < m; i++) {
 7             current_node = current_node -> next;
 8         }
 9         cout << current_node -> next -> data <<  " ";
10         Node<Type> * delete_node = current_node -> next;
11         current_node -> next = current_node -> next -> next;
12         delete delete_node;
13     }
14     cout << current_node -> data << endl;
15     delete current_node;
16 }

 

以上是关于链表 - Part II的主要内容,如果未能解决你的问题,请参考以下文章

粒子滤波 particle filter—从贝叶斯滤波到粒子滤波——Part-II(蒙特卡洛方法)

粒子滤波 particle filter—从贝叶斯滤波到粒子滤波——Part-II(蒙特卡洛方法)

代码随想录算法训练营第四天 | 24.两两交换链表中的节点19.删除链表的倒数第N个节点160.相交链表142.环形链表II

142. 环形链表 II

LeetCode 92. 反转链表 II

LeetCode Java刷题笔记—142. 环形链表 II