約瑟夫環鏈表解決算法

1.起源

        據說著名猶太曆史學家 Josephus有過以下的故事:在羅馬人佔領喬塔帕特後,39 個猶太人與Josephus及他的朋友躲到一個洞中,39個猶太人決定寧願死也不要被敵人抓到,於是決定了一個自殺方式,41個人排成一個圓圈,由第1個人開始報數,每報數到第3人該人就必須自殺,然後再由下一個重新報數,直到所有人都自殺身亡爲止。然而Josephus 和他的朋友並不想遵從。首先從一個人開始,越過k-2個人(因爲第一個人已經被越過),並殺掉第k個人。接着,再越過k-1個人,並殺掉第k個人。這個過程沿着圓圈一直進行,直到最終只剩下一個人留下,這個人就可以繼續活着。問題是,給定了和,一開始要站在什麼地方纔能避免被處決?Josephus要他的朋友先假裝遵從,他將朋友與自己安排在第16個與第31個位置,於是逃過了這場死亡遊戲。

2.鏈表實現

通過鏈表實現約瑟夫環比較容易理解

定義數據結構

#include <stdio.h>
#include <malloc.h>
#include <memory.h>
typedef struct Node
{
	int num;
	Node* next;
}Node;
創建鏈表

假設這裏我們創建有41個人的鏈表

Node* CreateList(int num)                       //傳遞參數生成多少個節點
{
	Node* node,*pTemp,*Head;
	int i=1;                                //這裏從1開始,不從0開始
	pTemp=(Node*)malloc(sizeof(Node));      //第一個節點單獨生成
	pTemp->num=i;
	pTemp->next=NULL;
	Head=pTemp;
	while(i<num)
	{
		node=(Node*)malloc(sizeof(Node));
		memset(node,0,sizeof(node));
		node->num=++i;;                 //節點從1-i,有i個節點
		node->next=NULL;
		pTemp->next=node;
		pTemp=node;		
	}	
	pTemp->next=Head;                      //鏈表的尾巴連接鏈表頭,形成一個循環鏈表
	return Head;
}

實際調用

int main()
{
	int num;
	printf("請輸入約瑟夫環的節點數目:");
	scanf("%d",&num);

	int Count;
	printf("請輸入報數間隔:");	
	scanf("%d",&Count);

	Node* p=CreateList(num);	
	Node *pDelete;

	//注意這裏生成的是一個循環鏈表,遍歷會產生無限循環
	while(p!=p->next)                      //循環鏈表判斷是否爲最後一個節點,如果是則p=p->next
	{
		for(int i=1;i<Count-1;i++)     //由於開始已經指向頭節點,鏈表指針移動的需要刪除節點的前一節點,實際上移動的次數爲(報數間隔-2)次
		{
			p=p->next;
		}
		pDelete=p->next;               //需要刪除的節點爲移動節點的下一節點
		printf("約瑟夫環出環順序:%d\n",pDelete->num);
		p->next=pDelete->next;         //鏈表重新連接,去除刪除節點
		p=pDelete->next;               //鏈表指針重新移動;
		free(pDelete);                 //刪除需要出列的節點
	}
	printf("約瑟夫環出環順序:%d\n",p->num);//最後一個出列的鏈表
        free(p);
	return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章