數據結構與算法學習筆記04(約瑟夫問題)

數據結構與算法學習筆記04(約瑟夫問題)

 

約瑟夫問題

據說著名猶太歷史學家 Josephus有過以下的故事:

在羅馬人佔領喬塔帕特後,39個猶太人與Josephus及他的朋友躲到一個洞中,39個猶太人決定寧願死也不要被敵人抓到,於是決定了一個自殺方式,41個人排成一個圓圈,由第1個人開始報數,每報數到第3人該人就必須自殺,然後再由下一個重新報數,直到所有人都自殺身亡爲止。然而Josephus和他的朋友並不想遵從,Josephus要他的朋友先假裝遵從,他將朋友與自己安排在第16個與第31個位置,於是逃過了這場死亡遊戲。

 

問題:

用循環鏈表模擬約瑟夫問題,把41個人自殺的順序編號輸出。

實現:

1、邏輯數組判斷法,用C++實現。

#include <iostream>
using namespace std;
void main()
{
	int N = 0, C = 0;
	cout << "Please enter the number of people:N=";
	cin >> N;
	cout << "Please enter:C=";
	cin >> C;
	//i,j是角標 s是計數
	int i = 0, j = 0, n = N, s = 0;
	int *a = new int[N];
	for (i = 0; i < N; i++)
	{
		a[i] = 1;
	}

	//人全部是殺死,停止循環
	while (n!=0)
	{
		//s計數
		s += a[j];
		if (C == s)
		{
			//做標記 標記爲殺死
			a[j] = 0;
			//置零
			s = 0;
			//殺死一個人 然後減1
			n--;
			if (n!=0)
			{
				//角標加1 打印當前位置
				cout << j + 1 << "->";
			}
			else
			{
				//打印結束
				cout << j + 1 << endl;
			}
		}
		//解決多圈循環後,角標的問題
		j = (j + 1) % N;
	}
	delete[]a;

2、用循環鏈表實現

 

循環鏈表

將單鏈表中終端結點的指針端由空指針改爲指向頭結點,就使整個單鏈表形成一個環,這種頭尾相接的單鏈表成爲單循環鏈表,簡稱循環鏈表。

 


注意:

這裏並不是說循環鏈表一定要有頭結點。

其實循環鏈表的單鏈表的主要差異就在於循環的判斷空鏈表的條件上,原來判斷head->next是否爲null,現在則是head->next是否等於head。

#include <iostream>
using namespace std;

/*宏定義和單鏈表類型定義*/
#define ListSize 100
typedef int DataType;
typedef struct Node
{
	DataType data;
	struct Node *next;
}ListNode, *LinkList;

//函數聲明
LinkList CreateCycList(int n);//創建一個長度爲n的循環單鏈表的函數聲明
void Josephus(LinkList head, int n, int m, int k); //在長度爲n的循環單鏈表中,報數爲編號爲m的出列
void DisplayCycList(LinkList head);//輸出循環單鏈表

void main()
{
	LinkList h;
	int n, k, m;
	cout << "輸入環中人的個數n=";
	cin >> n;
	cout << "輸入開始報數的序號k=";
	cin >> k;
	cout << "報數爲m的人出列m=";
	cin >> m;
	h = CreateCycList(n);
	Josephus(h, n, m, k);
}
void Josephus(LinkList head, int n, int m, int k)
/*在長度爲n的循環單鏈表中,從第k個人開始報數,數到m的人出列*/
{
	ListNode *p, *q;
	int i;
	p = head;
	q = head;
	for (i = 1; i < k; i++)     /*從第k個人開始報數*/
	{
		q = p;
		p = p->next;
	}
	while (p->next != p)
	{
		for (i = 1; i < m; i++) /*數到m的人出列*/
		{
			q = p;
			p = p->next;
		}
		q->next = p->next;  /*將p指向的結點刪除,即報數爲m的人出列*/
		cout << p->data<<" ";
		free(p);
		p = q->next;           /*p指向下一個結點,重新開始報數*/
	}
	cout << p->data << endl;//輸出最後一個結果
}

//創建一個循環鏈表
LinkList CreateCycList(int n)
/*宏定義和單鏈表類型定義*/
{
	LinkList head = NULL;
	ListNode *s, *r;
	r = NULL;
	int i;
	for (i = 1; i <= n; i++)
	{
		//創建後一個新的節點
		s = (ListNode*)malloc(sizeof(ListNode));
		s->data = i;
		s->next = NULL;
		if (head == NULL)
		{
			head = s;
		}
		else
		{
			r->next = s;
		}
		r = s;
	}
	//循環鏈表
	r->next = head;
	return head;
}


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