// 约瑟夫环.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<stdio.h>
#include<malloc.h>
#include<Windows.h>
/*常量定义*/
#define OK 0 //成功执行
#define Err_Memory -1 //内存分配错误
#define Err_InvalidParam -2 //输入参数无效
/*节点结构定义*/
typedef int ElemType; //元素类型为整形
typedef struct node {
ElemType id;
struct node* next;
}ListNode,*LinkList;
typedef int Status; //函数返回状态
/*下面函数功能为创建长度为n的带头节点的单循环链表,每个节点初始序号(id)为
创建该节点并加入到链表中的次序*/
Status CreateList(LinkList Head, int n)
{
ListNode *p, *s;
int i;
if (!Head) return Err_InvalidParam;
Head->next = Head; //初始化头结点
p = Head; //p指向头结点Head
for (i = 1; i <= n; i++)
{
s = (ListNode*) malloc(sizeof(ListNode));
s->id = i;
s->next = p->next;
p->next = s;
p = p->next;
}
return OK;
}
/*下面函数实现了约瑟夫环问题算法,其基本思想是对于非空的循环链表从第一个结点(序号为1)开始
报数,报数为m的结点被删除,其下一个结点作为新的报数起点,从1开始报数,直至循环链表中仅剩下
一个结点,该结点最后列出,代表幸存者*/
int Josephus(LinkList Head, int m)
{
int iCount = 1, iOrder = 0;
ListNode *pcur, *pprev, *pdel; //分别保存当前报数和当前出列次序
if (!Head) return Err_InvalidParam; //链表无效
pprev = Head; //pprev指向头结点
pcur = Head->next; //pcur指向第一个结点
while (pprev != pcur->next) //当链表仅剩一个结点
{
if (pcur != Head&&iCount == m)
{
pdel = pcur; //将当前要删除的结点保存到pdel
pprev->next = pcur->next; //删除当前结点
pcur = pcur->next; //pcur指向下一个结点,作为新的报数起点
iOrder++; //出列次序加1
printf("第%d个出列序号为:%d\n", iOrder, pdel->id); //输出出列序号
free(pdel);
iCount = 1; //重置报数,从1开始
}
else
{
if (pcur != Head) iCount++; //头结点不报数
pprev = pcur; //pprev指向当前结点
pcur = pcur->next; //pcur指向下一个结点
}
}
printf("第%d个出列序号为:%d\n", ++iOrder, Head->next->id);//输出最后出列序号
free(pcur);
free(pprev); //释放链表最后两个结点
}
/*主程序*/
void main()
{
int n, m;
LinkList Joseph; //声明循环链表
printf("请输入参与人数n:");
scanf_s("%d", &n);
printf("请输入报数上限m:");
scanf_s("%d", &m);
Joseph = (ListNode*) malloc(sizeof(ListNode));
if (CreateList(Joseph, n) != OK)
{
printf("链表创建错误!\n");
return;
}
if (Joseph->next == Joseph)
{
printf("参与人数输入错误!\n");
return;
}
printf("\n");
Josephus(Joseph, m);
system("pause");
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/u011233535/article/details/47319269