循环链表求解约瑟夫问题

来源:互联网 发布:技术军官知乎 编辑:程序博客网 时间:2024/05/16 09:11

题目描述
  有n人围成一圈,顺序排号。从第1个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来的第几号的那位。
输入
  初始人数n
输出
  最后一人的初始编号
样例输入
  3
样例输出
  2


  此题为约瑟夫问题,最直接的办法就是采用循环链表求解。

代码如下:

#include<iostream>using namespace std;/**附加头结点的循环链表的类定义:*作为私有数据成员,在链表的类定义中封装了2个链接指针:first、last,分别指示链表的附加头结点和链尾节点。*/template <class T>struct CircLinkNode     //链表结点类的定义{    T data;                     //数据域    CircLinkNode<T> *link;      //链指针域    CircLinkNode(CircLinkNode<T> *next = NULL):link(next) {}      //仅初始化指针成员的构造函数    CircLinkNode(T d,CircLinkNode<T> *next = NULL):data(d),link(next) {}      //初始化数据与指针成员的构造函数};template <class T>class CircList      //链表结点类定义{public:    CircList()      //构造函数,创建附加的头结点    {        first = last = new CircLinkNode<T>;        first->link = first;    }    CircList(CircList<T> &L);       //复制构造函数    CircLinkNode<T> *getHead()const     //返回附加头结点的地址    {        return first;    }    CircLinkNode<T> *getEnd()const     //返回附加尾结点的地址    {        return last;    }    void setEnd(CircLinkNode<T> *p)     //设置尾指针的位置    {        last = p;    }    CircLinkNode<T> *Locate(int i);     //搜索第i个元素的值    bool Insert(int i,T x);     //在第i个元素后插入xprotected:    CircLinkNode<T> *first,*last;       //头指针,尾指针};template <class T>CircLinkNode<T> *CircList<T>::Locate(int i){    if(i < 0) return NULL;    CircLinkNode<T> *current = first;    int k = 0;    while(current->link != first && k < i)    {        current = current->link;        k++;    }    return current;}template <class T>bool CircList<T>::Insert(int i,T x){    if(i < 0) return false;    CircLinkNode<T> *p = Locate(i);    CircLinkNode<T> *newNode = new CircLinkNode<T>(x);    newNode->link = p->link;    p->link = newNode;    if(p == last)     //如果插入的结点是在尾结点后,需要修改尾指针        last = newNode;    return true;}template <class T>CircList<T>::CircList(CircList<T> &L){    T value;    CircLinkNode<T> *srcptr = L.getHead();    CircLinkNode<T> *destptr = first = new CircLinkNode<T>;    while(srcptr->link != first)    {        value = srcptr->link->data;        destptr->link = new CircLinkNode<T>(value);        destptr = destptr->link;        srcptr = srcptr->link;    }    last = destptr;}/**函数Josephus用于选择,其参数包括人数值n和报数值m。该函数过程共执行n-1趟报数循环,每趟连续*计数m项,并从链表中删除第m个节点及打印该节点的编号,当只剩下一个结点时跳出循环,结束算法。*/template <class T>void Josephus(CircList<T> &Js,int n,int m){    CircLinkNode<T> *p = Js.Locate(1),*pre = NULL;    int i,j;    for(i = 0; i < n-1; i++)    {        for(j = 1; j < m; j++)        {            pre = p;            p = p->link;            if(p == Js.getHead())     //需要跳过附加头结点            {                pre = p;                p = p->link;            }        }        //  cout<<"出列的人是"<<p->data<<endl;        if(pre->link == Js.getEnd())      //删去尾指针所指的结点需要修改尾指针            Js.setEnd(pre);        pre->link = p->link;        delete p;        p = pre->link;        if(p == Js.getHead())     //需要跳过附加头结点        {            pre = p;            p = pre->link;        }    }}int main(){    CircList<int> clist;    int i,n;    cin>>n;    for(i = 1; i <= n; i++) clist.Insert(i,i);      //形成约瑟夫环    Josephus(clist,n,3);        //解决约瑟夫问题    cout<<clist.getEnd()->data;     //尾指针必定指向最后一个结点    return 0;}

参考文献
[1] 殷人昆编著. 数据结构——用面向对象方法与C++语言描述. 北京:清华大学出版社,2007.

0 0
原创粉丝点击