【數據結構】約瑟夫問題(鏈表法)


什么是約瑟夫問題?

約瑟夫問題:n個人圍成一圈,初始編號從1~n排列,從約定編號為x的人開始報數,數到第m個人出圈,接着又從1開始報數,報到第m個數的人又退出圈,以此類推,最后圈內只剩下一個人,這個人就是贏家,求出贏家的編號。

是不是有點點復雜,其實該問題歸結為模擬類型的算法題,根據題目要求模擬即可。

環形鏈表

image
1、先創建一個環形鏈表來存放元素:

2、然后一邊遍歷鏈表一遍刪除,直到鏈表只剩下一個節點,我這里就不全部演示了
image

那么,通過前面對環形鏈表的了解,以你的智慧應該會輕松解決簡單的約瑟夫問題了。

不妨我們加大難度,設有編號為1,2,3,...,n(n>0)個人按順時針順序圍坐一圈,沒人手持一個隨機產生的密碼(正整數)。現從第k個人開始順時針的方向以1開始報數,報數的上限第一個人持有的密碼m,報到m的人出列,然后將出列的人所持有的密碼作為新的m值,從下一個人開始重新從1開始報數,如此下去,直到最后一個人出列為止,要求設計一個程序模擬此過程,並輸出他們的列編號序列

問題分析

很顯然這是一個線性結構,可以用線性表來表示。進行的主要操作是報數、出列,這個相當於對線性表進行刪除操作,因此宜用用鏈表存儲結構,每個節點表示一個人。n個人圍城一圈循環報數,則利用單循環鏈表存儲結構更容易解決問題。
因此,
第一步需要創建單循環鏈表,每個節點存儲節點序號和密碼,密碼隨機生成(1-10)
第二步實現循環刪除操作,將密碼作為每次循環的步長(這里指的是距離)
第三步實現打印操作(跟隨第二步操作)

程序設計

/*單循環鏈表的存儲結構*/
typedef struct
{
    int num;//序號
    int pwd;//密碼
    struct Joseph *next;

}Joseph;

輸入設計

在一行中輸入總人數和第幾個人開始報數

輸入設計

首先輸出每個人的編號以及持有的密碼,其次輸出出列的編號次序,最后輸出幸存者。

基本操作

創建鏈表Joseph* creatList(Joseph* head,int n);
輸出每個人的序號以及密碼:void printList(Joseph* head,int n);
初始從第k個人開始報數,輸出出列次序:void outList(Joseph *head,int k);

程序代碼

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <malloc.h>
/*約瑟夫環問題
*單循環鏈表的創建
*打印單循環鏈表
*循環淘汰m,最后留下幸存者
*/
typedef struct
{
    int num;
    int pwd;
    struct Joseph *next;

}Joseph;
Joseph* creatList(Joseph* head,int n)
{
    int i;
    Joseph *p,*q;
    q = head;
    q->num = 1;
    q->pwd = rand()%10+1;


    for(i = 2;i<=n;i++)              //尾插法
    {
        p = (Joseph*)malloc(sizeof(Joseph));
        p->num = i;
        p->pwd = rand()%10+1;
        q->next = p;
        q = p;

    }
    p->next = head;

}
void printList(Joseph* head,int n)
{
    int i;
    Joseph *list;
    list = head;
    for(i = 0;i<n;i++)
    {
        printf("第%d位的密碼是%d\n",list->num,list->pwd);
        list = list->next;
    }

}
void outList(Joseph *head,int k)
{
    Joseph *p,*q;
    q = (Joseph*)malloc(sizeof(Joseph));
    p = head;
    int m;


    for(int i = 1;i<k;i++)              //找第k個節點,作為開始
    {
        q = p;
        p = p->next;
    }

    m = head->pwd;                       //第k個節點的密碼作為步長(這里指的是距離)
    while(p!=q)                          //當留下最后一個節點時p = q
    {
        for(int i = 1;i<m;i++)
        {
            q = p;
            p = p->next;
        }
        m = p->pwd;
        printf("%d ",p->num);
        q->next = p->next;
        free(p);
        p = q->next;
    }
    printf("\n幸存者:%d",q->num);
    free(p);


}



int main()
{
    Joseph *joseph;
    joseph = (Joseph*)malloc(sizeof(Joseph));
    int n;
    printf("輸入總人數:");
    scanf("%d",&n);

    creatList(joseph,n);
    printList(joseph,n);

    int k;
    printf("輸入從第幾個人開始報數:");
    scanf("%d",&k);

    outList(joseph,k);


    return 0;
}

約瑟夫問題:一行代碼就解決了 ————轉載


免責聲明!

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



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