1. 程式人生 > >約瑟夫環(Josephus)迴圈連結串列解決

約瑟夫環(Josephus)迴圈連結串列解決

關於約瑟夫環的簡單思路技巧
題目要求:
分析題目:
設編號為1,2,3,4…n的n個人順時針坐一圈,約定編號為K的人按順時針從1開始報數,數到m的人出列,他的下一位從1開始 報數…

預設第一次輸入剛開始的序號,之後選擇到誰就用誰的密碼,並把它刪掉。

思路分析:正常情況下取到P節點密碼m後,p.pre=p.next;for(i=0;im;i++);刪除節點,從他的下一個節點開始迴圈。一般情況可以,但是需要考慮密碼為0,1的特殊情況(密碼為1,需要刪除當前節點,以及第一次鍵入為1的特殊情況),較複雜。

現提供一種較簡單的思路:永遠讓指標指向實際連結串列開始應該數的第一個節點的前一個節點,從而避免考慮1,0的情況。首先開始第一次由鍵入開始序號時,先讓結點指標指向列表的最後一位,以鍵入的第一個數開始數,數到最後還是讓節點指向實際應該節點的前一位。直到最後連結串列裡只有一個節點時結束迴圈,並輸出接收到的順序。

話不多說,上程式碼:

while (p->next != L1)//找到尾指標,此時結點指標p在最後一位節點,第一次預設從第一個開始數,應該指向最後一位
	{
		p = p->next;
		r = p;
	}
while (p->next != p)
	{
		for (gg = 1; gg < ss; gg++)//指標移動( ss-1 )次,移動到將要刪除節點的前一個節點
		{
			p = p->next;//指標移動
		}
		m = p->next->date.m;//取出序號,以及下一次迴圈的ss
		ss = p->next->date.n;
		A[kk] = m;
		kk++;//新增到輸出陣列
		p->next = p->next->next;//刪除應該刪除的節點,此時指標還是旨在應該開始節點的上一位

	}

較完整程式碼

typedef struct number
{
	int m;//儲存其所在的位置
	int n;//儲存其資料
}number;
typedef struct londe
{
	number date;//資料型別儲存為結構體
	struct londe *next;//指向下一個節點
}londe, *Linklist;//指向結構體的指標
int A[7] = {0,0,0,0,0,0,0};//接受返回的順序,全域性,限制7個

Linklist *  inn()
{
	number S;
	Linklist *L = NULL;//建立空連結串列
	londe *q, *r = NULL;//新建節點,尾部插入新增一個尾指標
	int m = 1, n;//m:儲存的第幾個   n:儲存的數字
	printf("請輸入7個人所依次所拿的密碼\n");
	for (m; m < 8; m++)
	{
		scanf_s("%d", &n);//儲存到結構體裡
		S.m = m;//序號
		S.n = n;//密碼
		q = (londe *)malloc(sizeof(londe));
		q->date = S;//賦值給節點
		if (L == NULL)
		{
			L = q;//直接賦值第一個節點
		}
		else//判斷為空,本例中無用
		{
			r->next = q;
		}
		r = q;//尾指標總是指向最後一個節點
	}
	if (r != NULL)
		r->next = L;//指回去第一個節點
	return L;
}
int main()
{
	int i = 1,k;
	int kk = 0;//陣列專用
	int gg = 1;//判斷連結串列為1的情況
	int ss=1;//接受傳來的第一次定義的要迴圈的m值;
	int m, n;//接受返回連結串列結構體所包含的序號以及數值
	Linklist *L1 = NULL;//接受返回連結串列
	printf("請輸入第一次判斷的ss值\n\n");
	scanf_s("%d", &ss);
	L1 = inn();//接受迴圈的列表
	londe *p = L1;//新建節點指向L,遍歷L;
	londe *r=NULL;//尾指標

	while (p->next != L1)//找到尾指標,此時結點指標p在最後一位節點,第一次預設從第一個開始數,應該指向最後一位
	{
		p = p->next;
		r = p;
	}

	while (p->next != p)
	{
		for (gg = 1; gg < ss; gg++)//指標移動( ss-1 )次,移動到將要刪除節點的前一個節點
		{
			p = p->next;//指標移動
		}
		m = p->next->date.m;//取出序號,以及下一次迴圈的ss
		ss = p->next->date.n;
		A[kk] = m;
		kk++;//新增到輸出陣列
		p->next = p->next->next;//刪除應該刪除的節點,此時指標還是旨在應該開始節點的上一位

	}
	A[kk] = p->date.m;//最後一個數,提取新增
	for (i = 0; i < 7; i++)
	{
		printf("輸出順序為 %d \n",A[i]);
	}
	scanf_s("%d", &k);
	return 0;
}

在這裡插入圖片描述

算是第一次小總結吧,歡迎指正,另外思路是自己想的,如有和其他相重複/接近的,宣告不是抄襲哈!