1. 程式人生 > >約瑟夫問題(迴圈單鏈表求解)

約瑟夫問題(迴圈單鏈表求解)

約瑟夫問題是個有名的問題: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;
}