(2011.11.20)02_循环链表举例_约瑟夫(Joseph)环问题.cpp

来源:互联网 发布:java集合类有哪些 编辑:程序博客网 时间:2024/06/05 14:29

        这次感觉写得挺一般的,逻辑有点乱,功能与功能之间有点混杂,没有将它们一个个小的功能再细分出来。有待改进。大概用了四个小时,编写调试速度也是,有待提高,加油!

源代码:

// 02_循环链表举例_约瑟夫(Joseph)环问题.cpp/** * 问题描述及要求: * 01.假设有n个人坐在圆桌周围,从第s个人开始报数,报到m的人出列; * 02.然后再从下一个人开始报数,报到m的人又出列...直到所有的人都出列为止。 * 03.要求按出列的先后顺序输出每个人的编号。 **//** * 问题分析: * 1.该题目适合使用循环链表实现,这是因为圆桌的顺序数数就相当于一个不断循环的过程。 * 2.题目假设有n个人坐在圆桌周围,那么这里就使用链表来实现,想多少个人都可以,逐个插入。 * 3.根据题目要求,需要用到的数据成员有人的姓名,还有他在圆桌的位置编号(这个可以不要)。 *   这里可以确定需要在类中需要写出的成员函数有: *   01)构造和析构函数:链表的初始化是一定需要的。 *   02)插入函数:将一个个人的数据插入。 *   03)删除函数,当人需要出列的时候,相当于删除该人的数据。 *   04)输出到屏幕显示的函数:当人出列前,需要先打印出该人的数据(题目要求)。 *   05)查找函数:判断人出列时,需知该人是否在列中。 **/#include <iostream>// 输入输出需用#include <string>// 用户姓名存储方式#include <cstdlib>// system("pause")using std::cin;// using声明using std::cout;using std::endl;using std::string;// -------------------------------  类的结点(linknote)声明及定义 -----------------------------------class circulatelink;// 类声明,提前使用class linknote{private:friend class circulatelink;// 使链表成为友元类linknote * next;// 指向下一结点stringpeople;// 桌子上的人名int num;// 人名相应的序号public:linknote(linknote * n = NULL): next(n){}linknote(string p, int number, linknote * n = NULL): next(n), people(p), num(number){}};// -------------------------------  类(circulatelink)声明 -----------------------------------class circulatelink{private:// 用于知道链表中的数据数量enum size{defaultmaxsize = 15};// 默认最大值 int maxsize;// 实际最大值int leftsize;// 距离第一个数据的数量 // 用于链表的定位指针linknote * tail;// 尾指针linknote * fence;// 阑栅linknote * head;// 头指针public:// 构造析构函数circulatelink(int m = defaultmaxsize):              maxsize(m), leftsize(0), head(NULL), fence(NULL), tail(NULL){}~circulatelink()  {  for (fence = head; leftsize != 0; --leftsize)  {  fence = head;  head = head -> next;  delete fence;  }  leftsize = 0;  maxsize = 0;  fence = NULL;  tail = NULL;  head = NULL;  } // 功能函数int getmaxsize()    {return maxsize;}int getleftsize(){return leftsize;}void append(string p);// 插入函数void deldata(const int & startnumber, const int & runnumber);// 删除函数void print(const int & startnumber, const int & runnumber);// 显示函数bool search(const int & number);// 查找函数};// -------------------------------  类(circulatelink)定义 -----------------------------------/** * 函数名称:append * 函数参数:一个string型的变量p. * 函数功能:接受一个string型形参p插入到循环链表尾中,并使插入的姓名对应的号码为当前的链表大小加1。 *           该函数执行完成后,尾指针指向头指针,fence指针不变,maxsize不变,leftsize加1. **/void circulatelink::append(string p) // 插入函数{if (head ==NULL && tail == NULL){head = new linknote(p, leftsize + 1, NULL);tail = head;tail -> next = head;}else{    tail -> next = new linknote(p, leftsize + 1, head); tail = tail -> next;}++leftsize;return;}/** * 函数名称:search * 函数参数:一个常量int型变量number * 函数功能:在链表中查找是存在number元素,如果有,则返回真,没,则返回假 *           子函数结束后,fence指向头指针或number元素的上一指针。 **/bool circulatelink::search(const int & number)// 查找函数{if (maxsize == 0)return false;int i;for (leftsize = 0, fence = tail, i = 0; i != maxsize; fence = fence -> next, ++i){leftsize++;if (fence -> next -> num == number)return true;}return false;}/** * 函数名称:deldata * 函数参数:1.startnumber 整型常量,用于接受开始计算的用户名号码的编号。 *           2.runnumber 整型常量,用于接受题目要求中所说的报到数目。 * 函数功能:按照startnumber和runnumber计算出程序所要删除的元素的位置及将其删除。 **/void circulatelink::deldata(const int & startnumber, const int & runnumber)// 删除函数{// 该函数结合search函数使用,这里不进行调用,因为在主函数中已调用/* 该步已在print函数中执行for (int i = 0; i != runnumber; ++i){fence = fence -> next;// 根据要求将fence移位leftsize++;}*/linknote * temp = fence -> next;if (temp == head){head = fence -> next;tail -> next = head;leftsize = 0;}if (temp == tail){leftsize = maxsize - 1;tail = fence;}fence -> next = fence -> next -> next;delete temp;--maxsize;if (maxsize == 0)head = fence = tail = NULL;return;}/** * 函数名称:print * 函数参数:1.startnumber 整型常量,用于接受开始计算的用户名号码的编号。 *           2.runnumber 整型常量,用于接受题目要求中所说的报到数目。 * 函数功能:按照startnumber和runnumber计算出程序所要显示的函数并完成出列前的显示功能。 **/void circulatelink::print(const int & startnumber, const int & runnumber)// 删除函数{// 该函数结合search函数使用,这里不进行调用,因为在主函数中已调用for (int i = 0; i != runnumber; ++i){fence = fence -> next;// 根据要求将fence移位leftsize++;}cout << "-> 本次需要离开圆桌的是:" << fence -> next -> people << endl;return;}//------------------------------------------------------------------------------------------------------// ------------------------------------------ 整个程序流程(main)开始 -------------------------------int main(){// 程序开始 -- 对用户说明cout << " ------------------- 欢迎一起进行约瑟夫(Joseph)环问题的探讨 ------------------- \n";cout << "-> 题目说明:\n" << "    假设有n个人坐在圆桌周围,从第s个人开始报数,报到m的人出列," << "然后再从下一个人开始报数,报到m的人又出列...直到所有的人都出列为止。\n";cout << "-> 实验开始:\n" << "1. 开始安排座位\n" << "2. 开始报到\n"  << "3. 退出\n";cout << "-> 选择:";int choice();int select(choice());// 子功能的实现circulatelink seat;// 先声明变量及需要用到的函数void plansit(circulatelink & seat);// 实现功能2插入元素到链表void outsit(circulatelink & seat);// 实现功能3按顺序出链表start:switch(select){case 3:break;case 1: plansit(seat);case 2: {if (select == 2){cout << " ->请先选择1号功能,现在默认跳到1号功能。\n";select = 1;goto start;// 这里为了设计方便,简单地使用了if-goto语句}elseoutsit(seat);}}cout << "问题探讨成功,";system("pause");return 0;}// --------------------------- 主函数中的功能子函数 --------------------------------------------/** * 函数名称:choice * 函数参数:无 * 函数返回类型:int * 函数说明:本函数主要用于主菜单的功能选择, *           在该函数内,会要求用户输入一个范围1~3的正确的int型数值 * 最后返回该int型的数据。 **/int choice (){int ch;cin >> ch;while(!cin || ch > 3 || ch < 1){cin.sync();cin.clear();cout << "\n -> INPUT ERROR, ENTER AGAIN:";cin >> ch;cout << endl;}cout << endl;return ch;}/** * 函数名称:plansit * 函数参数:引用circulate类型的参数一个 * 函数返回类型:void * 函数说明:本函数功能为将15个数据插入到circulate链表中。 **/void plansit(circulatelink & seat){seat.append("people 01");seat.append("people 02");seat.append("people 03");seat.append("people 04");seat.append("people 05");seat.append("people 06");seat.append("people 07");seat.append("people 08");seat.append("people 09");seat.append("people 10");seat.append("people 11");seat.append("people 12");seat.append("people 13");seat.append("people 14");seat.append("people 15");cout << "-> 已成功为15位people安排座位,现在继续实现2号功能...\n\n";return;}/** * 函数名称:outsit * 函数参数:引用circulate类型的参数一个 * 函数返回类型:void * 函数说明:本函数功能为将链表中数据按题目要求方法依次出列。 **/void outsit(circulatelink & seat){for (int i = 1; seat.getmaxsize() != 0; ++i){// 01输入出列人号码int outsitnumber;bool errorsign(false);cout << "\n-> 请输入你希望第"<< i << "位开始报数的人的号码:";do{cin >> outsitnumber;// 001确定出列人输入正确if( !cin){cin.sync();cout << "\n -> INPUT ERROR, ENTER AGAIN:";cin.clear();errorsign = true;}// 002确定出列人位于链表中else if (seat.search(outsitnumber) == false){cout << "-> 该表中的" << outsitnumber << "已出列,请重新输入需要开始报数的人的号码:";errorsign = true;}elseerrorsign = false;}while(errorsign);// 02确定输入报数号码int runnumber;cout << "-> 请输入报数号码:";cin >> runnumber;while(!cin){cin.sync();cin.clear();cin >> runnumber;}// 03开始出列seat.print(outsitnumber, runnumber);seat.deldata(outsitnumber, runnumber);cout << endl;}return;}


调试运行过程:

 ------------------- 欢迎一起进行约瑟夫(Joseph)环问题的探讨 --------------------> 题目说明:    假设有n个人坐在圆桌周围,从第s个人开始报数,报到m的人出列,然后再从下一个人开始报数,报到m的人又出列...直到所有的人都出列为止。-> 实验开始:1. 开始安排座位2. 开始报到3. 退出-> 选择:5 -> INPUT ERROR, ENTER AGAIN:2 ->请先选择1号功能,现在默认跳到1号功能。-> 已成功为15位people安排座位,现在继续实现2号功能...-> 请输入你希望第1位开始报数的人的号码:15-> 请输入报数号码:1-> 本次需要离开圆桌的是:people 01-> 请输入你希望第2位开始报数的人的号码:1-> 该表中的1已出列,请重新输入需要开始报数的人的号码:0-> 该表中的0已出列,请重新输入需要开始报数的人的号码:2-> 请输入报数号码:5-> 本次需要离开圆桌的是:people 07-> 请输入你希望第3位开始报数的人的号码:2-> 请输入报数号码:0-> 本次需要离开圆桌的是:people 02-> 请输入你希望第4位开始报数的人的号码:3-> 请输入报数号码:0-> 本次需要离开圆桌的是:people 03-> 请输入你希望第5位开始报数的人的号码:4-> 请输入报数号码:5-> 本次需要离开圆桌的是:people 10-> 请输入你希望第6位开始报数的人的号码:5-> 请输入报数号码:0-> 本次需要离开圆桌的是:people 05-> 请输入你希望第7位开始报数的人的号码:6-> 请输入报数号码:934-> 本次需要离开圆桌的是:people 15-> 请输入你希望第8位开始报数的人的号码:4-> 请输入报数号码:0-> 本次需要离开圆桌的是:people 04-> 请输入你希望第9位开始报数的人的号码:6-> 请输入报数号码:0-> 本次需要离开圆桌的是:people 06-> 请输入你希望第10位开始报数的人的号码:8-> 请输入报数号码:0-> 本次需要离开圆桌的是:people 08-> 请输入你希望第11位开始报数的人的号码:9-> 请输入报数号码:7-> 本次需要离开圆桌的是:people 12-> 请输入你希望第12位开始报数的人的号码:9-> 请输入报数号码:8-> 本次需要离开圆桌的是:people 09-> 请输入你希望第13位开始报数的人的号码:11-> 请输入报数号码:2-> 本次需要离开圆桌的是:people 14-> 请输入你希望第14位开始报数的人的号码:11-> 请输入报数号码:2-> 本次需要离开圆桌的是:people 11-> 请输入你希望第15位开始报数的人的号码:7-> 该表中的7已出列,请重新输入需要开始报数的人的号码:6-> 该表中的6已出列,请重新输入需要开始报数的人的号码:13-> 请输入报数号码:9-> 本次需要离开圆桌的是:people 13问题探讨成功,请按任意键继续. . .


原创粉丝点击