1. 程式人生 > >【資料結構】1-2 約瑟夫環問題

【資料結構】1-2 約瑟夫環問題

這裡放出兩種不同的程式碼,一個是老師給的(較為複雜),還有一個是自己寫的。

自己寫的:

#include<iostream>
using namespace std;
struct Node {
    int data;            //資料單元
    Node *link;            //指向下一個結點
};
class Josephus
{
private:
    Node *head, *current;        //head是頭結點,current指向當前結點
    int sum;//儲存連結串列中元素的個數
public:
    Josephus();                
//無參建構函式,全部初始化為空 Josephus(int Snumber, int strnumber);//有參建構函式,Snumber為總數,strnumber為開始序號 ~Josephus();//解構函式 void del(Node *&p); void select(int num);//num為間隔數 void print(); }; Josephus::Josephus() { current = NULL; head = NULL; sum = 0; } Josephus::Josephus(int Snumber, int
strnumber) { sum = Snumber; head = new Node; head->data = strnumber; current = head; int dt = strnumber + 1; for (int i = 1; i < Snumber; i++) { Node *p; p = new Node; p->data = dt; current->link = p; current = p; dt
++; } current->link = head; } void Josephus::del(Node *&p) { Node *d = p->link; p->link = p->link->link; delete d; } void Josephus::select(int num) { int sont = 1; Node *p = head; while (sum!= 1) { if (sont % (num-1) == 0) { del(p); sum--; head = p; } sont++; p = p->link; } } void Josephus::print() { cout << "剩下的序號有:" << endl; Node *p = head; for (int i = 0; i < sum; i++) { cout << p->data << " "; p = p->link; } cout << endl; } Josephus::~Josephus() { /*Node *p = head->link; while (p!=head) { Node *de = p; p = p->link; delete de; }*/ head = NULL; current = NULL; }

測試程式碼:

#include"LinkList.h"
int  main()
{
    int Snum, stnum,num;
    cout << "請輸入總數以及開始序號:";
    cin >> Snum >> stnum;
    Josephus A(Snum, stnum);
    A.print();
    cout << "請輸入間隔數:";
    cin >> num;
    A.select(num);
    A.print();
    system("pause");
    return 0;
}

其實原理很簡單,就是通過迴圈連結串列不斷迴圈然後刪除就OK

標準程式碼:

//Circle.h
#include<iostream>
using namespace std;
template<class T>
struct Node   //結點結構
{
    T data;   //結點資料
    Node*link;
    Node() { link = NULL; }
    Node(T e, Node*next = NULL)
    {
        data = e;
        link = next;
    }
};
template<class T>
class CircleLinkList
{     //不帶表頭結點的迴圈連結串列類
private:
    Node<T> *current, *front; //current指向某結點,front指向current前驅
public:
    CircleLinkList() :current(NULL), front(NULL) {} //構建空迴圈連結串列
    CircleLinkList(T *d, int  mSize); //利用d陣列元素構建迴圈連結串列
    ~CircleLinkList();            //解構函式
    bool InsertAfter(const T&x);    //在current所指結點之後插入x
    bool RemoveCurrent(T&x);    //刪除current所指結點
    void movenext(int n = 1);    //current後移n次
    T GetCurrentData() { return current->data; }
    bool toLocatioin(T &t);//讓current指向t結點,若沒有則current不移動
    void Output() const;    //輸出迴圈連結串列
};  
class Joseph //    約瑟夫環類
{
private:
    int numOfBoy;  //圈中人數
    int startPosition;  //報數起始點
    int interval;     //報數間隔
public:
    Joseph(int boys, int start, int m) :
        numOfBoy(boys), startPosition(start), interval(m) {}//建構函式
    void setNumOfBoy(int num) { numOfBoy = num; }//重置圈中人數
    void setStartPosition(int start) { startPosition = start; }//重置起始點
    void setInterval(int inter) { interval = inter; }//重置報數間隔
    int GetWinner();//求得最終優勝者編號
    void print();   //輸出約瑟夫環
};
template<class T>
CircleLinkList<T>::CircleLinkList(T *d, int  mSize)
{    //建構函式,將d陣列中的mSize個元素建立迴圈連結串列
//採用前插法建立。
    int i;
    Node<T> *p;
    current = new Node<T>;
    current->data = d[mSize - 1];
    front = current;
    for (i = mSize - 2; i >= 0; i--)
    {
        p = new Node<T>(d[i], current);
        current = p;
    }
    front->link = current;
}
template<class T>
CircleLinkList<T>::~CircleLinkList()    //解構函式
{
    while (current != front)//銷燬迴圈連結串列
    {
        Node<T> *r = current;
        current = current->link;
        delete r;
    }
    delete current;
}
template<class T>
bool CircleLinkList<T>::InsertAfter(const T&x)
//在current所指結點之後插入x,current指向x結點
{
    Node<T> *s = new Node<T>(x);
    if (!s)return false;
    if (!current)  //原迴圈連結串列為空
        current = front = s->link = s;
    else //原迴圈連結串列非空
    {
        s->link = current->link;
        current->link = s;
        front = current;
        current = s;
    }
    return true;
}
template<class T>
bool CircleLinkList<T>::RemoveCurrent(T&x) //刪除current所指結點
{
    if (!current)//迴圈連結串列為空
        return false;
    x = current->data;
    if (current == front)//連結串列中只有一個元素
    {
        delete current;
        current = front = NULL;
    }
    else
    {
        front->link = current->link;//修改連結串列指標
        delete current;
        current = front->link;
    }
    return true;
}
template<class T>
void CircleLinkList<T>::Output() const     //輸出迴圈連結串列
{
    if (!current)//迴圈連結串列為空
        return;
    Node<T> *p = current;
    do
    {
        cout << p->data << "  ";
        p = p->link;
    } while (p != current);
    cout << endl;
}
template<class T>
void CircleLinkList<T>::movenext(int k)    //current後移k次
{
    for (int i = 1; i <= k; i++)
    {
        front = current; // front後移
        current = current->link; //current後移
    }
}
template<class T>
bool CircleLinkList<T>::toLocatioin(T &t)
//將current指向元素為t的結點,若沒有則current不移動
{
    if (!current)//迴圈連結串列為空
        return false;
    Node<T> *current1 = current, *front1 = front;
    while (current1->data != t) //尋找元素t
    {
        front1 = current1;
        current1 = current1->link;
        if (current1 == current)// 已尋找一圈沒有元素為t的結點
            return false;
    }
    current = current1; //current指向元素為t的結點
    front = front1;
    return true;
}
int Joseph::GetWinner()//獲得最終優勝者
{
    CircleLinkList<int> boys;
    for (int i = 0; i < numOfBoy; i++)//建立迴圈連結串列,編號依次為1~numOfBoy
    {
        int temp = i + 1;
        boys.InsertAfter(temp);
    }
    boys.toLocatioin(startPosition);   //找到報數起點
    cout << endl << "依次出列的小孩是:" << endl;
    for (int i = 1; i < numOfBoy; i++)   //numOfBoy-1個小孩出圈
    {
        int x;
        boys.movenext(interval - 1);  //報數
        boys.RemoveCurrent(x); //出圈
        cout << x << "  ";  //輸出出圈編號
    }
    return boys.GetCurrentData();  //返回優勝者編號
}
void Joseph::print()   //輸出約瑟夫環
{
    cout << "圈中人數:" << numOfBoy << endl;
    cout << "報數起始點:" << startPosition << endl;
    cout << "報數間隔:" << interval << endl;
}

測試程式碼

//測試程式碼.cpp
#include"Circle.h"
int main()
{
    int total, interv, startboy;
    cout << "請分別輸入人數,起始號碼和間隔數"<<endl;
    cin >> total >> startboy >> interv;
    Joseph jose(total, startboy, interv);
    jose.print();
    cout << "優勝者編號為: " << jose.GetWinner() << endl;
    system("pause");
    return 0;
}