···循环列表的经典应用-------环形链表的约瑟夫问题
//约瑟夫问题---环形链表
typedef struct ListNode ListNode;
//创建节点
ListNode* buyNode(int x)
{
ListNode* node=(ListNode*)malloc(sizeof(ListNode));
if(node==NULL)
{
exit(1);
}
node->val=x;
node->next=NULL;
return node;
}
//创建带环链表
ListNode* createCircle(int n)
{
ListNode* phead=buyNode(1);
ListNode* ptail=phead;
for(int i=2;i<=n;i++)
{
ptail->next=buyNode(i);
ptail=ptail->next;
}
//首尾相连,链表成环
ptail->next=phead;
return ptail;
}
int ysf(int n,int m)
{
//pcur是正常走的链表中的节点
//根据n创建带环链表
ListNode* prev=createCircle(n);
ListNode* pcur=prev->next;
int count=1; // !!!!!!!!!!!因为此时pcur已经指向了第一个节点
while(pcur->next!=pcur)//不是prec->next=pcur
{
//注意这里是两种情况
if(count==m)
{
//销毁pcur节点
prev->next=pcur->next;
free(pcur);
pcur=prev->next;
count=1;
}
else
{
//不需要销毁
prev=pcur;
pcur=pcur->next;
count++;// !!!!!!!!!!!!!!老忘
}
}
return pcur->val;
}
//以下为较难的用链表实现约瑟夫问题的代码
#include <malloc.h>
#define OVERFLOW -1
typedef struct ListNode ListNode;
typedef struct HeadNode HeadNode;
List JosephusProblem( int n, int m )
{
//create
List p;
p=(List)malloc(sizeof(HeadNode));
if(!p)
exit(OVERFLOW);
p->head=(ListNode*)malloc(sizeof(ListNode));
if(!(p->head))
exit(OVERFLOW);
//这样写不对,因为此时ptr的内容等于p->head->next中的内容,但其实这样的话ptr就是p->head->next->next的开头的头结点了
//那么就会导致p->head与新建立的链表分开,后面就会无法访问
//Position ptr=p->head->next;
Position ptr=p->head;
for(int i=1; i<=n; i++)
{
// ptr = ptr->next; //这里还是不对的
//这是代表把next里面的内容赋给ptr了,但是ptr的改变就不会影响head后面的节点了,只是在ptr的后面开辟了一系列节点
//链表的本质是让next指针来保存下一个节点的位置
//应该新开辟一个节点让链表的next指向该位置
//而不是把next的值赋值出来,再改变
// ptr = (ListNode*)malloc(sizeof(ListNode));
// if (!ptr)
// exit(OVERFLOW);
// ptr->data = i;
//printf("%d %d\n", ptr->data, i);
Position tmp = (ListNode*)malloc(sizeof(ListNode)); //是先开空间 然后让next指向这块空间
tmp->data = i;
ptr->next = tmp; //这样才是改变了 这个懂吗 这个就是让next指向新开辟的节点哦
ptr = tmp;
}
ptr->next=p->head->next;
//遍历找除去的人的顺序编号
int count=n;
int cnt=1;
List now;
now=(List)malloc(sizeof(HeadNode));
now->head=(ListNode*)malloc(sizeof(ListNode));
if(!now->head)
exit(OVERFLOW);
now->length=n;
Position nnow=now->head;
if(!nnow)
exit(OVERFLOW);
Position peo=p->head->next;
Position pre=p->head;
while(count>0)
{
if(cnt==m)
{
// free(peo);
Position ant;
ant=(ListNode*)malloc(sizeof(ListNode));
if(!ant)
exit(OVERFLOW);
ant->data=peo->data;
ant->next=NULL;
nnow->next=ant;
//这个地方切记要更新!!!!!!!!!!!!!!!!!!!!
nnow=ant;
count--;
cnt=1;
pre->next=peo->next;
peo=pre->next;
}
else
{
peo=peo->next;
pre=pre->next;
cnt++;
}
}
//前面给新开辟的结点的next赋空了,这个地方的结尾可以不用重复写
// nnow->next=NULL;
return now;
}