循环链表,顾名思义,循环的单链表,所以和单链表的区别也就是尾指针不再指向空,而是指向头节点,所以将首尾连接在了一起。
创建结构体
typedef struct Node
{
int data; //数据域
struct Node *Next; //指针域
}*PStu,Stu;
创建一个头结点,将指针域指向头结点,数据域置空
PStu createList()
{
PStu headNode = (PStu)malloc(sizeof(Stu));
headNode->Next = headNode;
return headNode;
}
对于循环链表来说,增,删,改,查的功能实现和单链表基本一样
增:(头插法和尾插法)
void ListByHead(PStu headNode,int number)
{
PStu NewNode = (PStu)malloc(sizeof(Stu)); //创建新结点
NewNode->data = number; //赋值
//头插法
NewNode->Next = headNode->Next;
headNode->Next = NewNode;
}
void ListByBear(PStu headNode,int number)
{
//创建一个指针接收头指针
PStu p = headNode;
//循环遍历到链表尾
while(p->Next != headNode)
{
p = p->Next;
}
if(p)
{
//创建新节点
PStu newNode = (PStu)malloc(sizeof(Stu));
//赋值
newNode->data = number;
p->Next = newNode;
p = newNode;
}
//尾指针一定要指向头结点
p->Next = headNode;
}
删:找到删除的前一个结点,和后一个结点相连在一起,然后free掉这个需要删除的结点
void deleteNode(PStu headNode,int data)
{
//遍历找到要删除的前一个结点
while(headNode->Next->data != data)
{
headNode = headNode->Next;
}
//创建新节点来存储删除结点
PStu k = (PStu)malloc(sizeof(Stu));
//当前删除节点
k = headNode->Next;
//k->Next:a删除结点的下一个结点
headNode->Next = k->Next;
//释放掉改结点
free(k);
}
查:之前的单链表查找的时候,运用for循环,现在也是,但是问题是,循环条件得变为
for(p = headNode;p->Next!=headNode;p = p->Next)
设置中间变量t来判断是否找到了对应的数字。
void cha(PStu headNode,int number)
{
PStu p;
int t;
for(p = headNode; p->Next != headNode; p=p->Next)
{
if(p->data == number)
{
printf("Yes");
t = 1;
break;
}
else
{
t = 0;
}
}
if(!t)
printf("No");
}
改:当查询到信息后需改就很简单了
void gai(PStu headNode,int number,int gai_number)
{
PStu p;
int t;
for(p = headNode; p->Next != headNode; p=p->Next)
{
if(p->data == number)
{
printf("Yes");
t = 1;
p->data = gai_number;
break;
}
else
{
t = 0;
}
}
if(!t)
printf("No");
}
这些便是循环链表的一点点内容,学会了循环链表,那一定要看看伟大的约瑟夫环,可以帮助你很好的掌握这些技术
问题描述:
约瑟夫(Flavius Josephu)是公元1世纪的一位著名历史学家。约瑟夫环(也称为约瑟夫问题)是一个数学的应用问题,可以简单地表述如下:
已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列,他的下一个人又从1开始报数,数到m的那个人又出列,依此规律重复下去,直到圆桌周围只剩下一个人为止。
【输入形式】参与游戏的总人数,退出游戏的数字以及游戏开始的数字。
【输出形式】游戏最后剩余的编号。
【样例输入】
15 4 2
【样例输出】
14
#include
#include
#include
#include
#include
typedef struct Node
{
int data;
struct Node *Next;
}*PStu,Stu;
PStu createList()
{
PStu headNode = (PStu)malloc(sizeof(Stu));
headNode->data = 1;
headNode->Next = headNode;
return headNode;
}
void ListByBear(PStu headNode,int N)
{
int i;
//创建一个指针接收头指针
PStu p = headNode;
//循环遍历到链表尾
while(p->Next != headNode)
{
p = p->Next;
}
for(i = 2;i<=N;i++)
{
//创建新节点
PStu newNode = (PStu)malloc(sizeof(Stu));
//赋值
newNode->data = i;
p->Next = newNode;
p = newNode;
}
//尾指针一定要指向头结点
p->Next = headNode;
}
void printList(PStu headNode)
{
PStu p = headNode;
while(p->Next!= headNode)
{
printf("%d ",p->data);
p = p->Next;
}
printf("%d",p->data);
printf("\n");
}
int main()
{
int i;
int M = 4;
PStu w = createList();
PStu r;
ListByBear(w,15);
printList(w);
int k = 2;
//遍历到开始的位置
for(i = 1;iNext;
}
while(w->Next != w)
{
for(i = 1;iNext;
}
printf("\n%d\n",w->data);
r->Next = w->Next;
w = w->Next;
}
printList(w);
}
借用尾插法将15个数字插入到循环链表中,因为是从第二个人计数,所以需要将链表的位置的移动到第二个结点的位置,while循环条件里面遍历链表,当尾指针域指向头指针的时候,结束。for循环里面,因为每次都是报数到第四个,所以需要遍历找到删除结点的前一个结点,每次循环的时候,都将结点赋值个新创建的结点,当遍历到删除结点前一个的时候,将结点(删除结点的前一个结点)保存起来,然后通过w = w->Next将结点后移一位,此时这个结点就是要删除的,此时将r的指针域指向删除结点的下一个结点,从而跳过了删除结点,而此时结点的位置还是当前的删除结点,所以将结点后移一位(w = w->Next)。