1 循环链表应用实例: 约瑟夫环问题:编号为1,2,...,n的的n个人按照顺时针方向围坐在一张圆桌周围,每个人持有一个密码(正整数),一开始任选一个正整数作为报数上限值m,从第一个人开始按照顺时针方向自1开始报数,报到m时停止报数,报m的那个人出列,将他的密码作为新的m值,从他顺时针方向的下一个人开始重新从1报数,数到m的人又出列:如此下去,直到圆桌周围的人全部出列为止。
循环链表:单链表的尾结点指向头结点(定义:循环链表最后一个节点的指针域由指向NULL改为指向头结点或第一个结点,就得到了单链形势的循环链表,并称为循环单链表,在循环单链表中,表中的所有结点被链在一个环上); L指向头结点,一般会设一个rail尾指针指向单链表中的最后一个元素;
2 一个例子 有两个带头结点的循环链表LA和LB,编写一个算法,将两个带头结点的循环单链表合并成一个,其头指针为LA 解决办法如下所示:
实现代码如下:
#include <iostream>
#include<stdlib.h>
#include<alloc.h>
using namespace std;
//ADT
typedef struct Node{
int data;
struct Node * next;
}Node;
typedef struct Node* LinkList;
int main(){}
/**
* 带头结点的循环单链表La和Lb合并为一个循环单链表,其头指针为La
*
*/
LinkList merge_1(LinkList LA, LinkList LB)
{
Node *p,*q;
p = LA;
q = LB;
while(p->next != LA)
p = p -> next;
while(q->next != LB)
q = q->next;
p->next = LB->next;
free(LB);
a->next=LA;
return(LA);
}
算法的时间复杂度分析:
在两个while中一次遍历,时间复杂度是O(n),所以采用带尾指针的循环链表,时间复杂度可以减低至O(1)
3 循环链表的特点:
(1)从表中任一结点出发都能访问到表中的所有结点;
(2)循环链表是对称的,为了判断起始位置,一般要设置头结点,头结点的设置也可将空表和非空表的逻辑状态及运算统一起来;
(3)循环链表的运算和线性链表基本一致,有时可简化某些运算
4 课后练习(约瑟夫环的实现)