5.約瑟夫問題(循環鏈表)


/* 此解法有一bug,假如有8個人,從第一個人開始數,每說到1就刪除,相當於自刪除,程序崩潰 */
約瑟夫問題,有n個人,編號為1,2,...,n,圍成一個圓圈,按照順時針方向從編號為k的人從1開始報數,報數為m的人出列,如此重復下去,直到所有的人都出列。編寫一個算法,要求輸入n,k,m,按照出列的順序輸出編號。

主要借助了兩個游標進行移動,p有兩個意義,第一,報數結束,p指向被刪除的結點,第二,刪除結點之后,p又指向開始報數的第一人。q作為橋梁進行銜接,因為需要刪除p指向的結點。兩個游標配合完成任務!

/*----------------完整代碼@映雪--------------*/

#include <iostream>
using namespace std;
typedef struct Node
{
    int data;
    struct Node *next;
}ListNode,*LinkList;
/*函數聲明*/
LinkList CreateCycList(int n);/*創建一個長度為n的循環單鏈表*/
void Josephus(LinkList head,int n,int m,int k);    /*長度為n的循環單鏈表中,報數為編號為m的出列*/

int main()
{        
    LinkList h;
    int n,k,m;
    printf("輸入環中人的個數n=");
    scanf("%d",&n);
    printf("輸入開始報數的序號k=");
    scanf("%d",&k);
    printf("報數為m的人出列m=");
    scanf("%d",&m);
    h=CreateCycList(n);
    Josephus(h,n,m,k);    
    return 0;            
}

/*-----------------算法核心段-----------------*/

void Josephus(LinkList head,int n,int m,int k)
{
    ListNode *p,*q;
    int i;
    p=head;
    for(i=1;i<k;i++)/*從第k個人開始報數,將p先移到這個位置,准備開始*/
    {
        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;/*q作為輔助[銜接]p左右的兩個結點,等價於刪除p*/
        printf("%4d",p->data);
        free(p);/*釋放結點p*/
        p=q->next;            /*p指向下一個結點,重新開始報數*/
    }
    printf("%4d\n",p->data);/*只剩最后一個結點!*/
}

/*----------------建立循環鏈表------------------*/

LinkList CreateCycList(int n)
/*建立鏈表,用兩個游標s,r配合完成!*/
{
    LinkList head=NULL;
    ListNode *s,*r;
    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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM