1. 程式人生 > >使用連結串列解決約瑟夫環的問題

使用連結串列解決約瑟夫環的問題

已知n個人(以編號1,2,3…n分別表示)圍坐在一張圓桌周圍。從編號為1的人開始報數,數到m的那個人出列;他的下一個人又從1開始報數,數到m的那個人又出列;依此規律重複下去,直到圓桌周圍的人全部出列,問最後一個出環的人的原編號。

用在單鏈表中刪除一個結點的思想來解決此題
設一個沒有頭結點指標的單鏈表。一個指標指向此單鏈表中間的一個結點(不是第一個,也不是最後一個結點),將該結點從單鏈表中刪除,要求時間複雜度O(1)。
圖示分析:
這裡寫圖片描述
程式清單:

#include <iostream>
#include <malloc.h>
using namespace std;
typedef struct NODE
{
    int data
; struct NODE *next; }Node, *LinkList; void CreatByTail(LinkList L) { Node *p, *tail; tail = L; int i = 0; while (i < 7) { p = (Node*)malloc(sizeof(Node)); p->data = i + 1; tail->next = p; tail = tail->next; i++; } tail->
next = NULL; } void OutPut(LinkList L) { Node *p; p = L; while (p != NULL) { cout << p->data << " -> "; p = p->next; } cout << "\b\b\b\b " << endl; } void Delete(LinkList L, Node *p) { Node *late; late = p->next; p->
data = late->data; p->next = late->next; free(late); } int main(void) { LinkList L; L = (LinkList)malloc(sizeof(Node)); L->data = 0; CreatByTail(L); OutPut(L); Node *p; p = L->next->next->next; Delete(L, p); OutPut(L); return 0; }

解決約瑟夫環的問題:
首先建立一個沒有頭指標的環形連結串列,並從1到length對其初始化,即為每個人的原始編號;
定義一個計數器count,若其指向待刪除的前一個,則將它的下一個結點刪除。
程式清單:

#include <iostream>
#include <malloc.h>
//連結串列解決約瑟夫環的問題
using namespace std;

typedef struct NODE
{
    int data;
    struct NODE *next;
}Node, *Linklist;

//尾插法建立一個環形連結串列
void CreatByTail(Linklist L, int length)
{
    Node *p, *tail;
    tail = L;
    int i = 1;
    while (i < length)
    {
        p = (Node*)malloc(sizeof(Node));
        p->data = i + 1;
        tail->next = p;
        tail = tail->next;
        i++;
    }
    tail->next = L;//使尾指標指向頭結點,建立環形連結串列
}

void YueSeFu(Linklist L, int key)
{
    Node *cur;
    cur = L;
    int count = 1;
    while (cur->next != cur)//若相等,表明環中只剩最後一人,則迴圈結束
    {
        //若計數到出局號碼前一個的位置cur,則說明cur->next是需要被刪除的結點
        if (count == key - 1)
        {
            //藉助late記錄cur->next的位置
            Node *late;
            late = cur->next;

            //刪除cur->next(即late)
            cur->next = late->next;
            free(late);

            //使count再從1開始計數,查詢下一個出局號碼
            count = 1;
            cur = cur->next;
        }
        else
        {
            cur = cur->next;
            count++;
        }
    }
    cout << "最後一個人原編號是: " <<cur->data << endl;
}
int main(void)
{
    int length = 0;
    int key = 0;
    Linklist L;
    L = (Linklist)malloc(sizeof(Node));
    L->data = 1;

    printf("請輸入人數: ");
    scanf("%d", &length);
    CreatByTail(L, length);

    printf("請輸入出局編號: ");
    scanf("%d", &key);
    YueSeFu(L, key);
    return 0;
}

執行截圖:
這裡寫圖片描述