【資料結構】1-2 約瑟夫環問題
阿新 • • 發佈:2018-11-19
這裡放出兩種不同的程式碼,一個是老師給的(較為複雜),還有一個是自己寫的。
自己寫的:
#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, intstrnumber) { 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; }