1. 程式人生 > 實用技巧 >線性表應用三:約瑟夫環問題

線性表應用三:約瑟夫環問題

任務描述

約瑟夫環是典型的線性表,可以使用不帶頭結點的迴圈單鏈表進行儲存。本關任務,通過使用不帶頭結點的迴圈電連結串列儲存約瑟夫環,並模擬約瑟夫環的報數出圈過程,得出約瑟夫環出圈序列。輸入n(1<=n<=100)為約瑟夫初始結點個數,輸入m(1<=m<=100)為一輪報數數值,輸出出圈序列。 例:n=9 m=3

相關知識

據說著名猶太曆史學家約瑟夫(Josephus)有過以下的故事:在羅馬人佔領喬塔帕特後,39 個猶太人與約瑟夫及他的朋友躲到一個洞中,39個猶太人決定寧願死也不要被敵人抓到,於是決定了一個自殺方式,41個人排成一個圓圈,由第1個人開始報數,每報數到第3人該人就必須自殺,然後再由下一個重新報數,直到所有人都自殺身亡為止。然而約瑟夫和他的朋友並不想遵從。約瑟夫要他的朋友先假裝遵從,他將朋友與自己安排在第16個與第31個位置,於是逃過了這場死亡遊戲。約瑟夫問題可以抽象為:n 個人圍成一圈 (3<=n<=100)(從零開始編號),從第一個人開始報數,第m個將被殺掉 (1<=m<=n),最後剩下一個,其餘人都將被殺掉 。例如n = 6,m = 5,被殺掉的順序為:4, 3, 5, 1, 2, 0。

程式設計要求

本關的程式設計任務是補全step8/polynomailList.h檔案中的 createJoselink ()、move ()、deleteNextnode ()、printJoseque() 函式,分別實現約瑟夫環的建立,指標固定步數的移動、後繼結點的刪除、約瑟夫環刪除序列列印,這四個函式的具體說明如下:

// 函式createJoselink:建立包含n個結點(不帶頭結點)的迴圈單鏈,結點的資料值以此是1~n // 引數:n-約瑟夫環初始結點個數 // 返回值:約瑟夫環不帶頭迴圈單鏈表的首個結點指標 node* createJoselink(int t);

// 函式move:指標向前移動step步 // 引數:p-起點指標指向的結點位置,step-指標在迴圈單鏈中向前移動的步數 // 返回值:從p指標所指向的結點位置,向前移動step步後所指向的結點位置 node* move(node* p, int step);

// 函式deleteNextnode:刪除p指標所指向的下一個結點 // 引數:pre-指向待刪除結點的前驅結點(注意:當迴圈單鏈只剩下一個結點時,pre指標指向的結點即待刪除結點) void deleteNextnode(node* pre);

// 函式printJoseque:輸出約瑟夫環刪除序列,編號之間用一個空格隔開 // 引數:n-約瑟夫環初始總人數,m-一輪報數值 void printJoseque(int n, int m);

評測說明

本關中包含兩個檔案分別是: step8/joseLink.h :此檔案為學員檔案,包含不帶頭結點的迴圈單鏈表結構約瑟夫環問題相關處理函式,其中createJoselink () 、move () deleteNextnode ()、printJoseque()為學員待實現函式。 step8/test.cpp:此檔案為評測檔案(含main函式),引用“joseLink.h”,主要用於輸入約瑟夫環初始人數n和一輪報數數值m,並呼叫printJoseque()函式輸出約瑟夫環刪除序列。 (上述兩個檔案可通過點選在程式碼取的右上角資料夾中的step8資料夾中檢視)

輸入輸出說明

輸入約瑟夫環初始人數n(1<=n<=100),輸入一輪報數數值m(1<=m<=100),輸出約瑟夫環元素刪除序列,例如:

測試輸入: 6 5 預測輸出: 5 4 6 2 3 1

測試輸入: 9 3 預測輸出: 3 6 9 4 8 5 2 7 1

test.h

#include "joseLink.h"
int main()
{
    int n, m;    
    // 輸入初始總人數n,和一輪報數值m
    cin >> n >> m;
    // 輸出約瑟夫出圈序列,兩編號之間用一個空格隔開
    printJoseque(n,  m);
    return 0;
}

joseLink.h

#include <iostream>
using namespace std;

//單鏈表結點結構定義
struct node
{
    int  data;
    node* next;  // 指標域,指向下一個結點
};

// 函式createJoselink:建立包含n個結點(不帶頭結點)的迴圈單鏈,結點的資料值以此是1~n 
// 引數:n-約瑟夫環初始結點個數
// 返回值:約瑟夫環不帶頭迴圈單鏈表的首個結點指標
node* createJoselink(int t);

// 函式move:指標向前移動step步 
// 引數:p-起點指標指向的結點位置,step-指標在迴圈單鏈中向前移動的步數
// 返回值:從p指標所指向的結點位置,向前移動step步後所指向的結點位置
node* move(node* p, int step);

// 函式deleteNextnode:刪除p指標所指向的下一個結點
// 引數:pre-指向待刪除結點的前驅結點(注意:當迴圈單鏈只剩下一個結點時,pre指標指向的結點即待刪除結點)
void deleteNextnode(node* pre);

// 函式printJoseque:輸出約瑟夫環刪除序列,編號之間用一個空格隔開
// 引數:n-約瑟夫環初始總人數,m-一輪報數值
void printJoseque(int n, int m);

// 函式delList:刪除連結串列,釋放空間
// 引數:h-連結串列頭指標
void delList(node* h);

// 函式printList:輸出連結串列,每個資料之間用一個空格隔開
// 引數:h-連結串列頭指標
//void printList(node* h);

void delList(node* h)
{
    node* p = h; //指標p指向頭結點,第一個要刪除的結點
    while (p) //這個結點是存在的
    {
        h = h->next; //頭指標h指向下一個結點(下一個結點的地址存在當前結點的指標域中,即h->next中
        delete p; //刪除p指向的結點
        p = h; //p指向當前的頭結點,即下一個要刪除的結點
    }
}

node *newNode(int data) 
{ 
   node *temp = new node; 
   temp->next = temp; 
   temp->data = data; 
} 
node* createJoselink( int t)
{
    // 請在此新增程式碼,補全函式createJoselink
   /********** Begin *********/
    node *p, *q;
    p = (node*)malloc(sizeof(node));
    p->next = NULL;
    p->next = p;

    for (int i = 1; i <= t; i++)
    {
        q = (node*)malloc(sizeof(node));
        q->data = i;
        q->next = p->next;
        p->next = q;
    }
    return p;
    /********** End **********/

}

node* move(node* p, int step)
{
    // 請在此新增程式碼,補全函式move
    /********** Begin *********/
    for(int i = 0; i < step ; i++) //移動到刪除節點位置        
    {
        p = p->next;
    }
    return p;
    /********** End **********/
}

void deleteNextnode(node* pre)
{
   
    // 請在此新增程式碼,補全函式deleteNextnode
    /********** Begin *********/
    node *q = pre->next;
    pre->next = q->next;
    free(q);
    /********** End **********/

}

void printJoseque(int n, int m)
{
    // 請在此新增程式碼,補全函式printJoseque
    /********** Begin *********/
    node *head = newNode(1); 
    node *prev = head; 
    for (int i = 2; i <= n; i++) 
    { 
        prev->next = newNode(i); 
        prev = prev->next; 
    } 
    prev->next = head; // Connect last 
                       // node to first 
  
    /* while only one node is left in the 
    linked list*/
    node *ptr1 = head, *ptr2 = head; 
    while (ptr1->next != ptr1) 
    { 
        // Find m-th node 
        int count = 1; 
        while (count != m) 
        { 
            ptr2 = ptr1; 
            ptr1 = ptr1->next; 
            count++; 
        } 
  
        /* Remove the m-th node */
        ptr2->next = ptr1->next;
        printf ("%d ", ptr1->data);  
        free(ptr1); 
        ptr1 = ptr2->next;
    }
    printf ("%d ", ptr1->data);   
    /********** End **********/

}