約瑟夫問題(迴圈單鏈表求解)
阿新 • • 發佈:2019-02-18
約瑟夫問題是個有名的問題:N個人圍成一圈,從第K個開始報數,第M個將被殺掉,最後剩下一個,其餘人都將被殺掉。例如N=6,K=1,M=5,被殺掉的順序是:5,4,6,2,3,1。
/*用迴圈連結串列實現約瑟夫問題*/
#include<iostream>
#include<stdlib.h>
using namespace std;
typedef struct LNode
{
int data;
struct LNode *next;
}LNode,*LinkList;
void Josephus(int n,int m,int k)
{
LinkList p,r,list =NULL;
int i;
for(i=1;i<=n;i++)
{
p=(LinkList)malloc(sizeof(LNode));//申請一個新的鏈結點
p->data=i;//存放第i個結點的編號
if(list==NULL)
list=p;
else
r->next=p;
r=p;
}
p->next=list;//至此,建立一個迴圈連結串列
p=list;
for(i=1;i<k;i++)
{
//r指向第k個結點,p指向第k-1個結點
r=p;
/*請注意,此行不是多餘的,因為當k!=1,但m=1時如果沒有這條語句,此時刪除動作無法完成*/
p=p->next;
}//此時p指向第1個出發結點
while(p->next!=p)
{
for(i=1;i<m;i++)
{
r=p;
p=p->next;
}//p指向第m個結點,r指向第m-1個結點
r->next=p->next;//刪除第m個結點
printf("%4d" ,p->data);//依次輸出刪除結點的編號
free(p);//釋放被刪除結點的空間
p=r->next;//p指向新的出發結點
}
printf("\n最後剩餘的結點是:%4d\n",p->data);//輸出最後一個結點的編號
}
int main()
{
int n,m,k;
cout<<"請輸入結點的個數:"<<endl;
scanf("%d",&n);
cout<<"請輸入報道報數週期是:"<<endl;
scanf("%d",&m);
cout<<"請輸入從第幾個數開始報數:"<<endl;
scanf("%d",&k);
Josephus(n,m,k);
return 0;
}
/*任務:
一群小孩圍成一圈,任意假定一個數m,從第一個小孩起,順時針方向數,每數到第m個小孩時,該小孩便離開。小孩不斷離開,圈子不斷縮小。最後剩下的一個小孩便是勝者。求勝者的編號?
要求
以面向物件技術進行程式設計
建立環狀連結串列類
程式便於維護與擴張:如易於對小孩數量n和數數間隔m進行變化
改變獲勝者數量,使其可設為任意值
可中途增加小孩人數
*/
/*結構體實現*/
#include<iostream>
#include<stdlib.h>
using namespace std;
typedef struct LNode
{
int data;
struct LNode *next;
}LNode,*LinkList;
class Jos
{
private:
int n,m,k,last;//結點個數,報數週期,報數起始數.
int index;//標記剩餘人數,標記插入時r第一個的指向.
LinkList list,r;
public:
Jos(){list=NULL;r=NULL;}
void set();
void Josephus();
void Insert();
void is_add();
void print_Josephus();
}XPY;
void Jos:: set()//插入函式
{
cout<<"請輸入結點的個數:"<<endl;
scanf("%d",&n);
cout<<"請輸入報道報數週期是:"<<endl;
scanf("%d",&m);
cout<<"請輸入從第幾個數開始報數:"<<endl;
scanf("%d",&k);
cout<<"請輸入剩餘個數:"<<endl;
scanf("%d",&last);
}
void Jos:: Josephus()//建立一個迴圈連結串列
{
LinkList p;
int i;
index=n;//結點個數賦初值
for(i=1;i<=n;i++)
{
p=(LinkList)malloc(sizeof(LNode));//申請一個新的鏈結點
p->data=i;//存放第i個結點的編號
if(list==NULL)
list=p;
else
r->next=p;
r=p;
}
p->next=list;//至此,建立一個迴圈連結串列
}
void Jos:: Insert()//迴圈連結串列的插入
{
LinkList p=(LinkList)malloc(sizeof(LNode));
p->data=n+1;
n++;//個數加1
index++;//個數加1
p->next=r->next;
r->next=p;
r=p;
}
void Jos:: is_add()//中途新增函式
{
printf("是否新增成員(Y/N)\n");
char ch;
cin>>ch;
while(1)
{
system("cls");
ch=tolower(ch);//轉換為全小寫的
if(ch=='y')
Insert();
else if(ch=='n')
break;
else
printf("輸入有誤\n");
system("cls");
printf("是否繼續新增成員(Y/N)\n");
cin>>ch;
}
}
void Jos:: print_Josephus()//迴圈的執行
{
LinkList p=list;
for(int i=1;i<k;i++)
{
r=p;
/*請注意,此行不是多餘的,因為當k!=1,但m=1時如果沒有這條語句,此時刪除動作無法完成*/
p=p->next;
}//此時p指向第1個出發結點
printf("刪除的結點號是:\n");
while(index>last)
{
for(int i=1;i<m;i++)
{
r=p;
p=p->next;
}//p指向第m個結點,r指向第m-1個結點
r->next=p->next;//刪除第m個結點
printf("%3d",p->data);//依次輸出刪除結點的編號
free(p);//釋放被刪除結點的空間
// is_add();
p=r->next;//p指向新的出發結點
index--;//刪除結點,個數減1
}
while(index--)//勝利者的輸出
{
printf("\n最後剩餘的結點是:%4d\n",p->data);//輸出最後一個結點的編號
p=p->next;
}
}
int main()
{
XPY.set();
XPY.Josephus();
XPY.print_Josephus();
return 0;
}