簡單約瑟夫環的循環單鏈表實現(C++)


剛剛接觸C++以及數據結構,今天做了第一次嘗試用C++和數據結構解決問題,問題是基於約瑟夫環問題的簡單版。

  • 先來看看約瑟夫環問題的介紹:

    約瑟夫環是一個數學的應用問題:已知n個人(以編號1,2,3...n分別表示)圍坐在一張圓桌周圍。從編號為k的人開始報數,數到m的那個人出列;他的下一個人又從1開始    報數,數到m的那個人又出列;依此規律重復下去,直到圓桌周圍的人全部出列。(摘自百度百科)

    程序的輸入應該由三個值組成(n, k, m),接下來程序將會自動運行,本文假設每次都從第一個人開始報數,所以是做了一些簡化,但是換湯不換葯。

  • 接下來將分部介紹程序的組成

    首先是頭文件,命名為circle_single_linked_list.h

    基本結構:

template <typename Object>
class circleSingleLinkedList{
private:

/*循環單鏈表的每個的節點定義
*結構簡單,所以使用struct
*具體實現請看下文
*/
struct Node{ }; public:

/*內嵌類iterator
*是鏈表中的一個位置的抽象(abtracts the notion of a position)
*類比vector<>的iterator
*在類外的調用方法為:circleSingleLinkedList<int>::iterator ....
*本文省去了對於const_iterator類型的定義
*/
class iterator{ }; public:

  /*循環鏈表實現
*由構造函數(含默認實參),big three都沒有...(程序比較簡陋)
*begin()返回表頭位置
*insert以及erase是實現約瑟夫環的主要手段
*循環鏈表只有2個數據成員, theSize存儲鏈表節點個數, head為頭指針, 指向鏈表中的第一個節點
*具體實現見下文
*/ circleSingleLinkedList(
const Object& x = Object()){ } iterator begin()const{ } int size(){ return theSize; } bool empty(){ return size() == 0; } iterator insert(iterator itr, const Object& x){ } iterator erase(iterator itr){ } void print(ostream& out){ } private: int theSize; Node* head; };

    由於編寫的是模板類,所以將類的定義,成員函數的實現,以及內嵌類的實現都放在了一個頭文件中,本人剛剛接觸C++,目前了解的情況是:模板類最好不要用        separate compilation,因為可能會造成complicated looking syntax,具體是什么我目前也不清楚,需要繼續學習。

 

  • 接下來是各部分的具體實現
1 struct Node{
2         Object data; //用於存放各個節點的數值,在約瑟夫環問題中,存放不同人的編號
3         Node* next;  //每個單鏈表節點的指向下一個節點的指針
4 
5         Node(const Object& d = Object(), Node* n=NULL) //默認構造函數
6         : data(d), next(n) {}
7 };

內嵌類iterator的實現

//iterator類主要包含了運算符重載:解引用,prefix++,postfix++,==,!=,具體的使用可以類比vector<>::iterator的使用方法.
1
class iterator{ 2 public: 3 iterator(): current(NULL){} 4 5 Object & operator*()const{ 6 return current->data; 7 } 8 9 iterator & operator++(){ 10 current = current->next; 11 return *this; 12 } 13 14 iterator operator++(int){ 15 iterator old = *this; 16 ++(*this); 17 return old; 18 } 19 20 bool operator==(const iterator& rhs)const{ 21 return current == rhs.current; 22 } 23 24 bool operator!=(const iterator& rhs)const{ 25 return !(*this == rhs); 26 } 27 28 protected:  //protected一般在有繼承的情況下使用,這個地方我就懶得改了 29 Node* current; //iterator是鏈表中一個具體位置的抽象, current指針用於指向所選定的節點 30 31 iterator(Node* p): current(p){} //iterator類型主要使用的構造函數 32 33 friend class circleSingleLinkedList<Object>;//使外層包含類也可以訪問iterator的非public成員 34 };

剩下的就是循環單鏈表的定義,在這里我就想着重講一下insert以及erase方法,begin()函數,默認構造函數(初始化頭結點)以及print函數(輸出鏈表各節點的data數據)這里就不提了。

insert(位置,數值),因為這是單鏈表,不能通過一個位置來確定它之前的位置(沒有指向前一個節點的指針),所以insert是在itr所確定的元素的后面插入一個新節點,函數返回新節點處的位置.
需要注意的是,insert與erase都是的返回類型都是copy passing的,具體原因我暫時還搞不清楚.
1
iterator insert(iterator itr, const Object& x){ 2 Node* p = itr.current; 3 Node* newNode = new Node(x, p->next); 4 p->next = newNode; 5 theSize++; 6 return iterator(newNode); 7 }

 erase函數

 erase(位置),刪除itr位置之后的元素,原理與insert相同,如果刪除的元素師頭節點,則將頭節點分配給原頭節點的下一個元素
1
iterator erase(iterator itr){ 2 Node* p = itr.current; 3 if(p->next == head) 4   head = head->next; 5 Node* old = p->next->next; 6 delete p->next; 7 p->next = old; 8 theSize--; 9 return itr; 10 }
  •  接下來我們來看一下main函數中的實際應用情況,也就是約瑟夫環問題。
 1 int main()
 2 {
 3     circleSingleLinkedList<int> iList(1);  //初始化循環鏈表,其包含一個頭節點,由head指針指向,頭指針指向的元素就是約瑟夫環問題中的第一個人,編號為1
 4 
 5     int n;
 6     cout << "n=" << endl;    //輸入約瑟夫環問題中的人數n
 7     cin >> n;
 8 
 9     int i=2;
10     circleSingleLinkedList<int>::iterator iter = iList.begin();  //初始化iter指向頭節點
11     while(i <= n){
12         iter = iList.insert(iter,i);  //為鏈表添加節點元素,每一次都添加到iter所抽象的元素的下一個,其數值為i
13         ++i;
14     }
15 
16     iter = iList.begin();    //iter重新指向表頭
17 
18     int m;
19     cout << "m=" << endl;    //輸入約瑟夫環問題中的步值m,也就是每做一次刪除所數的一個步長
20     cin >> m;
21 
22     i = 1;
23     while(iList.empty() != true){
24         while(i < m){      //由於erase是刪除iter所指向的下一個元素,而不是刪除iter,所以iter需要代表被刪除元素之前的一個元素.
25             ++iter;
26             ++i;
27         }
28         iter = iList.erase(iter);
29         iList.print(cout);    //每做一次刪除就輸出顯示整個list.
30         i = 1;
31     }
32 
33     cout << endl;
34 
35     return 0;
36 }
  • 最后結果:

         

        輸入n=10, m=3, 由於我默認程序從第一個節點(1)開始數,所以第一個刪除的節點是4(也就是編號為4的人),刪除之后,從4的下一個節點(5)開始數3,第二個刪除的元素為8,以此類推.

 

  • 總結:這是第一次用數據結構和C++解決實際問題,也是第一次發博文,目前對數據結構的理解是,其是對內存空間進行某種特定規律的管理的一種手段,以特殊的策略實現功能程序的優化。

             希望繼續練習,熟悉更多的結構。

      2013-11-08 11:12:23


免責聲明!

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



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