前言:循环链表时一种头尾相接的链表。其特点是无须增加存储量,仅对表的链接方式稍作改变,即可使得表处理更加方便灵活。
如何构成循环单链表?
在单链表中,将终端结点的指针域NULL改为指向表头结点的或开始结点,就得到了单链形式的循环链表,并简单称为单循环链表。
为什么用尾指针表示循环单链表?
在很多实际问题中,表的操作常常是在表的首尾位置上进行,此时头指针表示的单循环链表就显得不够方便.如果改用尾指针rear来表示单循环链表,则查找开始结点a1和终端结点an都很方便,它们的存储位置分别是(rear–>next) —>next和rear,显然,查找时间都是O(1)。因此,实际中多采用尾指针表示单循环链表。
下面是一个循环单链表的例子:
/*
copyright(c)2012 三江学院 电子信息工程
* 文件名称:josephus.c
* 文件标识:见配置管理计划书
* 摘要:约瑟夫问题,共有N个犹太人,包括约瑟夫和他的朋友,这N个人决定自杀,
但是约瑟夫和他朋友都不想死,于是他们设计了一个死亡游戏 ,最终他俩免于一死。
游戏规则:N个人围成一圈,然后从某个人开始数数(此人算作第一个),第M个人自
杀,有一个人死后,从他下一个人开始数数。
* 当前版本:1.1
* 作者:黄路
* 完成日期:2012年7月1日
*/
#include <stdio.h>
#include <stdlib.h>
typedef struct Jew
{
int number;
struct Jew *next;
}Jew;
int main(int argc, char *argv[])
{
Jew *jew;//指向链表头
Jew *r; //指向当前节点
int N; //总人数
int M; //自杀间距
int i;
printf("input number of jew(N) and interval(M):\n");
scanf("%d, %d", &N, &M);
jew = (Jew*)malloc(N * sizeof(Jew)); //为链表分配内存
// memory check
if ( NULL== jew)
{
printf(" no memory!\n");
return 0;
}
r = jew;
//init list
for (i = 1; i < N; i++)
{
r->number = i;
r->next = jew + i; //在连续内存中操作
r = r->next;
}
r->number = N;
r->next = jew;//形成单循环链表
printf("suicide order:\n");
while (r != r->next)
{
//实现跳跃式杀人,第M个自杀
for (i = 1; i < M; i++)
{
r = r->next;
}
printf("%4d\n", r->next->number);
r->next = r->next->next; //被杀的人从链表上消失!!
}
printf("\n when N = %d and M = %d\nJosephus, hiding in position %d survives.\n", N, M, r->number);
free(jew);
return 0;
}