约瑟夫环--普通解法和伪链表法

第一种方法代码:

#include <stdio.h>
#include <malloc.h>

#define N 9
#define doom 4

void lowJoseph(int num, int doomLength);

void lowJoseph(int num, int doomLength) {
	int alive = N;					//存活人数
	int *circle = NULL;				//定义一个数组,里面元素值均为0
	int index = 0;					//令初始下标为0
	int ss = 0;						//进行数数

	circle = (int*)calloc(sizeof(int), num);
	while(alive > 0) { 				//只要有幸存者,就继续出圈
		ss += 1 - circle[index];	
		if(ss == doomLength) {		//如果数数到这个人,进行下列操作
			printf("%d  ", index + 1);	//输出这个人的序号
			circle[index] = 1;			//将这个人状态改为出圈状态
			alive--;					//圈内存活的人数减一
			ss = 0;						//报数从0重新开始
		}
		index = (index + 1) % num;		//下标+1,即轮到下一个人,但因为圈是循环的,因此与圈最大人数取余
										//当数到圈内最后一个人时,重新从第一个人开始
	}

	free(circle);	//所有人出圈后,释放内存
}

int main() {
	lowJoseph(N, doom);
}

第一种方法虽然好理解,但是很耗费时间,因为出圈之后的人还需要参与判断(判断元素值是否为0才能选择进行的操作),而第二种方法,如果该人出圈,则下一次操作直接略过此人,在操作人数很多的时候,这会大大减少运行时间!

第二种方法代码:

#include <stdio.h>
#include <malloc.h>

#define N 		9
#define doom 	4

void middleJoseph(int num, int doomLength);

void middleJoseph(int num, int doomLength) {
	int alive = num;	//存活人数
	int count = 0;		//计数器
	int curIndex = 0;	//当前人下标
	int preIndex = num - 1;		//前一个人是下标
	int *circle = NULL;
	int index;

	circle = (int *)calloc(sizeof(int), num);	//申请一个空间
	for(index = 0; index < num; index++) {		//初始化链表
		circle[index] = (index + 1) % num;
	}

	while(alive > 0) {		//当圈内还有人
		count++;	//计数
		if(doomLength == count) {	//当计数大小与厄运数字相同时,进行出圈操作
			//出圈要进行的操作
			printf("%d  ", curIndex + 1);		//输出出圈人的位置
			alive--;	//将存活的人数减一
			count = 0;	//计数器置零
			circle[preIndex] = circle[curIndex];	//真正的出圈操作
		} else {
			preIndex = curIndex;	//继续处理下一个人
		}
		curIndex = circle[curIndex];	//当前人向后移动
 	}
 	printf("\n");

 	free(circle);	//释放链表
}

int main() {
	middleJoseph(N, doom);
}

第二段代码,在进行时,一定要认真进行一次变量跟踪,不然会不好理解

如果有错误的话,还希望大家多多指教~

猜你喜欢

转载自blog.csdn.net/szy2333/article/details/80627941