这个程序是通过约瑟夫问题进行改编。
利用循环链表,每个节点都有自己的ID,同时持有其他节点的ID。
每找到一个ID,就对其进行删除。
编译环境:vs2012
#include <stdio.h>
#include <stdlib.h>
#ifndef NULL
#define NULL 0
#endif
enum BOOL
{
FALSE, TRUE
};
typedef struct node
{
int ID; //每个节点的id
int GetId; //其他节点的id,通过这个可以查找下一个节点
struct node *next;
}Node, *Link;
Link CreaList(int idmax);
Link GetNode(int id, int password);
Link StatGame(Link head, int passw, int idmax);
void Print(Link head);
int EmptyList(Link head);
/*************************************
名称:CreaList[初始化链表]
调用:Crealist(int idmax)
作用:生成并初始化一个用户设定大小的链表
参数:idmax,需要设定链表长度的值
返回:返回头指针
*************************************/
Link CreaList(int idmax)
{
Link head, pnow, ptemp;
int idnow = 1, pass;
head = pnow = NULL;
do
{
while(1)
{
printf("请输入当前节点的密码:");
if ( scanf_s("%d", &pass, 1) == 1 )
{
break;
}
printf("输入错误,请重新输入\n");
}
ptemp = GetNode(idnow, pass);
if(!head)
{
head = (Link)malloc(sizeof(Node));
head->next = ptemp;
pnow = ptemp;
}
else
{
pnow->next = ptemp;
pnow = ptemp;
}
idnow = idnow + 1;
}while (idnow <= idmax);
//设置结尾指向头节点;
pnow->next = head->next;
free(head);
return pnow->next;
}
/*************************************
名称:GetNode[获取节点]
调用:GetNode(int id, int password)
作用:生成,初始化节点并返回
参数:id,节点的序号。password,节点所持密码
返回:返回节点的指针
*************************************/
Link GetNode(int id, int password)
{
Link tenode;
tenode = (Link)malloc(sizeof(Node));
//初始化
tenode->ID = id;
tenode->GetId = password;
tenode->next = NULL;
return tenode;
}
/*************************************
名称:StatGame[改版的约瑟夫]
调用:StatGame(Link head, int passw, int idmax)
作用:用约瑟夫自杀功能对链表操作
参数:head,要操作的链表节点
返回:返回操作后的头节点
*************************************/
Link StatGame(Link head, int passw, int idmax)
{
Link tailpoint, pfree;
int num = 0;
int ifalg = 1; //结束标志
tailpoint = head; //节点尾指针,删除某节点后,用来连接上一个节点。
if(EmptyList(head))
{
printf("表空,无法进行!\n");
exit(1);
}
while (ifalg)
{
passw = passw % idmax;
while (passw != tailpoint->next->ID)
{
if (num>9)
{
printf("[木有找到或被删除。]\n");
break;
}
tailpoint = tailpoint->next;
num++;
}
pfree = tailpoint->next;
tailpoint->next = pfree->next; //将 a->b->c 变成 a->c,实现从链表中删除
passw = pfree->GetId; //备份密码,用来查找下一个节点的指针
printf("第%d个人出列,密码:%d\n", pfree->ID, pfree->GetId);
//检测是否为最后一个结点
if (pfree == tailpoint)
{
ifalg = 0;
}
free(pfree); //释放才是真正的删除
num = 0;
}
return tailpoint;
}
/*************************************
名称:Print[打印]
调用:Print(Link head)
作用:打印指定的循环链表
参数:head,链表头节点
*************************************/
void Print(Link head)
{
Link temp;
temp = head;
if(EmptyList(head))
{
printf("表空,无打印数据!\n");
return;
}
while (head->next != temp)
{
printf("%d ->", head->ID);
head = head->next;
}
printf("%d", head->ID);
}
/*************************************
名称:EmptyList[空表检测]
调用:EmptyList(Link head)
作用:检测传入的循环链表是否为空;
参数:head,要检测的链表头节点
返回:如果为空返回true,反之false;
*************************************/
int EmptyList(Link head)
{
if ( !head )
{
return TRUE;
}
else
{
return FALSE;
}
}
int main()
{
Link head;
int idmax, password;
printf("请输入要设定的链表长度:");
scanf_s("%d", &idmax, 1);
printf("请输入初始的密码:");
scanf_s("%d", &password, 1);
head = CreaList(idmax);
printf("*****************当前链表数据*****************\n\n");
Print(head);
printf("\n\n");
printf("*****************运行约瑟夫后*****************\n\n");
head = StatGame(head, password, idmax);
return 0;
}