简单约瑟夫环的循环单链表实现(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

转载于:https://www.cnblogs.com/yijiem/p/yijiem.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值