C++循环链表实现约瑟夫问题
2013-09-24 16:17
465 查看
约瑟夫问题(有时也称为约瑟夫斯置换,是一个出现在计算机科学和数学中的问题。在计算机编程的算法中,类似问题又称为约瑟夫环。又称“丢手绢问题”)
据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
我写了一个循环链表来实现约瑟夫问题,其实没必要这么复杂,只需要用一个vector或者是数组即可,以下是我写的代码:
1.循环链表头文件:
2.循环链表.cpp文件
3.约瑟夫函数以及主函数的.cpp文件
如果您那么细心的看完代码后,发现有什么问题,希望您能够给我留言提出,只有不断发现不足,才能一直前进!!!
据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
我写了一个循环链表来实现约瑟夫问题,其实没必要这么复杂,只需要用一个vector或者是数组即可,以下是我写的代码:
1.循环链表头文件:
#ifndef __CircleList_H__ #define __CircleList_H__ #include <iomanip> #include <iostream> #include <ctime> #include <cassert> using namespace std; #define LEN 20 #define RANLEN 100 typedef int ElemType; typedef struct Lnode { ElemType data; //值域 Lnode *next; //next指针 }Lnode; class CircleList { private: Lnode *head;//头指针 Lnode *curr;//当前指针 int count; //循环链表中元素个数 public: CircleList();//构造函数,只有一个头结点 ~CircleList(){delete head;}//析构函数 Lnode *CreateCircleList(const int& n,const int& mark);//创建循环链表,n表示的是循环链表中的元素个数,mark为1的时候表示升序,-1的时候表示降序,0的时候表示随机 void TraverseCircleList(); //遍历整个循环链表 // void InsertNode(const ElemType& item,int pos); //向循环链表中指定位置插入节点 bool IsEmpty(){ return head->next == head; } //判断链表是否为空 // Lnode *Index(int pos); //返回指定位置的Lnode指针 ElemType GetElem(int pos); //返回指定位置的data值 Lnode *Next(); //返回下一个节点的指针 Lnode *Reset(int pos); //将curr指针指向指定的位置并返回 ElemType DeleteNext(); //删除curr指针指向的下一个节点 Lnode* GetCurrNode(); //返回curr指针 ElemType DeletePosNode(int pos); //删除指定位置的节点 }; #endif
2.循环链表.cpp文件
#include "stdafx.h" #include "CircleList.h" CircleList::CircleList() { head = new Lnode; head->next = head; curr = NULL; count = 0; } Lnode *CircleList::CreateCircleList(const int& n,const int& mark) { int i,j,min; ElemType temp; ElemType a[LEN]; Lnode *tempNode = NULL; srand((unsigned)time(NULL));//用于产生随机数的种子 count = n; for(i = 0; i < LEN; i++ ) { a[i] = rand()%RANLEN; //产生100以内的随机数,保存在a数组中,a数组的长度为LEN=20个,也即n不能超过20 cout<<a[i]<<setw(3); if( i == LEN -1 ) cout<<endl; } //选择排序 for( i = 0; i < LEN-1; i++) { min = i; for( j = i+1; j < LEN;j++ ) { if( a[min] > a[j] ) min = j; } if( min != i ) { temp = a[min]; a[min] = a[i]; a[i] = temp; } } for( i = 0; i < LEN; i++ ) { cout<<a[i]<<setw(3); if( i == LEN - 1) cout<<endl; } head->next = curr = tempNode = new Lnode; switch(mark) { case -1://表示降序排列 curr->data = a[0]; curr->next = head; for(i = 1;i < n; i++ ) { curr = new Lnode; curr->data = a[i]; tempNode->next = curr; tempNode = tempNode->next; curr->next = head; } break; case 0://表示随机排列 curr->data = rand()%RANLEN; curr->next = head; for( i = 1; i < n; ++i ) { curr = new Lnode; curr->data = rand()%RANLEN; tempNode->next = curr; tempNode = tempNode->next; curr->next = head; } break; case 1://表示升序排列 curr->data = a[LEN-1]; curr->next = head; for( i = 2; i <= n; ++i ) { curr = new Lnode; curr->data = a[LEN-i]; tempNode->next = curr; tempNode = tempNode->next; curr->next = head; } break; default:cerr<<"mark error!"<<endl; } return head; } void CircleList::TraverseCircleList() { Lnode *search = head; cout<<"遍历链表结果:"<<endl; while( search->next != head ) { search = search->next; cout<<search->data<<setw(3); } } ElemType CircleList::GetElem(int pos) { int i = 0; Lnode *search = head; for( i = 0; i < pos; i++ ) { search = search->next; } return search->data; } ElemType CircleList::DeletePosNode(int pos) { assert( pos > 0 ); int i = 0; ElemType data; Lnode *search = head->next; curr = head; for( i = 1; i < pos; i++ ) { curr = curr->next; search = search->next; } curr->next = search->next; search->next = NULL; data = search->data; delete search; count--; return data; } Lnode *CircleList::Next() { if( curr->next == head ) curr = curr->next->next; else curr = curr->next; return curr; } Lnode *CircleList::Reset(int pos) { int i; curr = head; for( i = 0; i < pos; i++ ) { curr = curr->next; } return curr; } ElemType CircleList::DeleteNext() { ElemType data; Lnode *search = NULL; if( curr->next != head ) { search = curr->next; curr->next = curr->next->next; data = search->data; search->next = NULL; delete search; } else { search = curr->next->next; curr->next->next = search->next; data = search->data; search->next = NULL; delete search; } return data; } Lnode* CircleList::GetCurrNode() { return curr; }
3.约瑟夫函数以及主函数的.cpp文件
// CircleListAndJosephProblem.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include "CircleList.h" //约瑟夫问题,n表示人数,m表示数多少个数,x表示第一次从哪个人开始数数 void JosephProblem(int n,int m,int x) { int i,j; CircleList cl; cl.CreateCircleList(n,1); cout<<"未报数之前人的编号顺序:"<<endl; cl.TraverseCircleList(); cout<<endl; cl.Reset(x-1); for( i = 0; i < n-1; i++ ) { for( j = 0; j < m-1; j++ ) cl.Next(); cout<<cl.DeleteNext()<<"元素被删除!"<<endl; } cout<<"最后剩下的元素为:"<<cl.GetCurrNode()->data<<endl; } int _tmain(int argc, _TCHAR* argv[]) { /* CircleList cl; cl.CreateCircleList(10,1); cl.TraverseCircleList(); cl.DeletePosNode(2); cout<<"删除后的链表为:"<<endl; cl.TraverseCircleList(); */ JosephProblem(10,3,1); return 0; }
如果您那么细心的看完代码后,发现有什么问题,希望您能够给我留言提出,只有不断发现不足,才能一直前进!!!
相关文章推荐
- 解析C++ 浮点数的格式化输出
- 深入分析C++中几个最不常用的关键字
- c++中inline的用法分析
- 深入解析C++ Data Member内存布局
- 从汇编看c++中默认构造函数的使用分析
- C++的sstream标准库详细介绍
- 基于C++自动化编译工具的使用详解
- 浅谈C++中的string 类型占几个字节
- C/C++ 宏详细解析
- 深入分析C++中两个大数相乘结果不正确的问题
- 探讨C++中数组名与指针的用法比较分析
- 深入解析C++中的引用类型
- C++可变参数的实现方法
- 基于C++类型重定义的使用详解
- C++中Operator类型强制转换成员函数解析
- C++ 关于STL中sort()对struct排序的方法
- c++中const的使用详解
- 深入C++四种强制类型转换的总结
- 深入C++可见性与生命期的区别详解
- c++中冒号(:)和双冒号(::)的使用说明