双环链
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了双环链相关的知识,希望对你有一定的参考价值。
将一个双链表首尾相连的时候就是一个环链表,一一相连,循环不息- 数据结构
typedef struct node
{
int data; //数据域
struct node *next; //指针域
struct node *prep;
}NODE_t;
这里和双向链表是一致的,指针域包含前驱和后继
- 创建
NODE_t *CreatNodeList()
{
NODE_t *head = NULL;
head = (NODE_t *)malloc(sizeof(NODE_t));
if(!head)
exit(-1);
head->next = head;
head->prep = head;
return head;
}
当创建空链时,将头节点的前驱和后继都指向自己
- 插入
int InsertNode(NODE_t *head,int data)
{
NODE_t *cur = NULL;
if(!head)
exit(-1);
cur = (NODE_t *)malloc(sizeof(NODE_t));
if(!cur)
exit(-1);
cur->data = data;
/*
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
next ===> head->next;
prev ===> head;
*/
// 链表在插入时有一个规则,不易出错,就是让新产生的节点先有所指向
cur->prep = head;
cur->next = head->next;
head->next->prep = cur;
head->next = cur;
return 0;
}
-
查找
NODE_t *findNode(NODE_t *head,int data) { NODE_t *p = head->next; while( p != head) { if(p->data == data) { break; } p = p->next; } if(head == p) { printf("sorry,%d is not in the list\n",data); return NULL; } return p; }
-
删除
int DeleteNodeOfList(NODE_t *pfind) { pfind->prep->next = pfind->next; pfind->next->prep = pfind->prep; free(pfind); pfind = NULL; return 0; }
6,修改
int UpdateNode(NODE_t *head,int olddata,int newdata) { NODE_t *p = findNode(head,olddata); if(p) { p->data = newdata; } return 0; }
只要找得到需要操作的指针,剩下的就是操纵数据域的问题
- 遍历打印
void showList(NODE_t *head)
{
NODE_t *p = NULL;
p = head->next;
while(p != head)
{
printf("%d ==> ",p->data);
p = p->next;
}
printf("end..\n");
}
当再回到头结点时,意味着遍历了一遍,此处可以结束了
- 得到list的长度
int ListNodeLen(NODE_t *head)
{
int len = 0;
NODE_t *p = NULL;
p = head->next;
while(p!=head)
{
len++;
p = p->next;
}
return len;
}
9.排序
int sortList(NODE_t *head)
{
int i = 0,j = 0;
int listlen = 0;
int tmpData = 0;
NODE_t *p = NULL;
// 使用冒泡排序,不动指针域,比较数据域,使用临时变量,将有大小之别的节点的数据域交换
// 得到链表长度,方便冒泡
listlen = ListNodeLen(head);
// 指到首节点
p = head->next;
for(i = 0;i < listlen-1;i++)
{
// 每一轮从头开始
p = head->next;
for(j = 0;j<listlen - i-1;j++)
{
// 将小值排在前面
if(p->data > p->next->data)
{
tmpData = p->data;
p->data = p->next->data;
p->next->data = tmpData;
}
p = p->next;
}
}
return 0;
}
约瑟夫问题:
所有人围成一圈
顺时针报数,每次报到q的人将被杀掉
被杀掉的人将从房间内被移走
然后从被杀掉的下一个人重新报数,继续报q,再清除,直到剩余一人
这个问题可以用环链解决,当符合条件的结点删除,直到最后一个结点
假设每次报数报3的人杀掉
NODE_t *p = NULL;
int cnt = 0;
p = head->next;
while(1)
{
// 头节点无效,指向下一个节点,继续循环
if(p == head)
{
p = p->next;
continue;
}
printf("ID:%d 报数 %d\n",p->data,++cnt);
if(cnt == 3)
{ // 报数为3的人,杀掉
cnt = 0;
NODE_t *ptemp = p->next; // 杀掉后,后续节点将无法找到,所以需要记录后续节点
printf("will kill id %d\n",p->data);
DeleteNodeOfList(p);
p = ptemp;
showList(head);
}
else
{ // 不杀人的情况,继续报数
if(ListNodeLen(head) != 1)
{
p = p->next;
}
else // 杀至最后一个人,游戏结束
{
break;
}
}
// sleep(1);
}
printf("the Index of people who can survive is %d\n",p->data);
有时候想,这些数学问题充满了残忍,比如说小学数学的启蒙就是从打鸟开始,这个有是排成一圈杀人,包括好多医学书籍,不知道为了一本书后面充满了多少残忍和血腥。。。。
链表还是很有用的,比如看linux驱动代码就可以看到,有好多数据结构中包含一个 struct list_head head;这种数据结构,其实内核大神们将链表的指针域单独封装出来,然后,讲个东东包到任意一个结构体内,这个结构体就变成一个环链,这个可以参考 linux/list.h头文件,可以看到人家实现的很牛逼,大道致简,很简单的抽象封装,组合起来,造成了一个操作系统的底层数据结构,值得学习
以上是关于双环链的主要内容,如果未能解决你的问题,请参考以下文章