【数据结构】1-2 约瑟夫环问题

这里放出两种不同的代码,一个是老师给的(较为复杂),还有一个是自己写的。

自己写的:

#include<iostream>
using namespace std;
struct Node {
    int data;            //数据单元
    Node *link;            //指向下一个结点
};
class Josephus
{
private:
    Node *head, *current;        //head是头结点,current指向当前结点
    int sum;//存储链表中元素的个数
public:
    Josephus();                //无参构造函数,全部初始化为空
    Josephus(int Snumber, int strnumber);//有参构造函数,Snumber为总数,strnumber为开始序号
    ~Josephus();//析构函数
    void del(Node *&p);
    void select(int num);//num为间隔数
    void print();
};
Josephus::Josephus()
{
    current = NULL;
    head = NULL;
    sum = 0;
}
Josephus::Josephus(int Snumber, int strnumber)
{
    sum = Snumber;
    head = new Node;
    head->data = strnumber;
    current = head;
    int dt = strnumber + 1;
    for (int i = 1; i < Snumber; i++)
    {
        Node *p;
        p = new Node;
        p->data = dt;
        current->link = p;
        current = p;
        dt++;
    }
    current->link = head;

}
void Josephus::del(Node *&p)
{
    Node *d = p->link;
    p->link = p->link->link;
    delete d;
}
void Josephus::select(int num)
{
    int sont = 1;
    Node *p = head;
    while (sum!= 1)
    {
        if (sont % (num-1)  == 0)
        {
            del(p);
            sum--;
            head = p;
        }
        sont++;
        p = p->link;
    }

}
void Josephus::print()
{
    cout << "剩下的序号有:" << endl;
    Node *p = head;
    for (int i = 0; i < sum; i++)
    {
        cout << p->data << " ";
        p = p->link;
    }
    cout << endl;
}
Josephus::~Josephus()
{
    /*Node *p = head->link;
    while (p!=head)
    {
        Node *de = p;
        p = p->link;
        delete de;
    }*/
    head = NULL;
    current = NULL;
}

测试代码:

#include"LinkList.h"
int  main()
{
    int Snum, stnum,num;
    cout << "请输入总数以及开始序号:";
    cin >> Snum >> stnum;
    Josephus A(Snum, stnum);
    A.print();
    cout << "请输入间隔数:";
    cin >> num;
    A.select(num);
    A.print();
    system("pause");
    return 0;
}

其实原理很简单,就是通过循环链表不断循环然后删除就OK

标准代码:

//Circle.h
#include<iostream>
using namespace std;
template<class T>
struct Node   //结点结构
{
    T data;   //结点数据
    Node*link;
    Node() { link = NULL; }
    Node(T e, Node*next = NULL)
    {
        data = e;
        link = next;
    }
};
template<class T>
class CircleLinkList
{     //不带表头结点的循环链表类
private:
    Node<T> *current, *front; //current指向某结点,front指向current前驱
public:
    CircleLinkList() :current(NULL), front(NULL) {} //构建空循环链表
    CircleLinkList(T *d, int  mSize); //利用d数组元素构建循环链表
    ~CircleLinkList();            //析构函数
    bool InsertAfter(const T&x);    //在current所指结点之后插入x
    bool RemoveCurrent(T&x);    //删除current所指结点
    void movenext(int n = 1);    //current后移n次
    T GetCurrentData() { return current->data; }
    bool toLocatioin(T &t);//让current指向t结点,若没有则current不移动
    void Output() const;    //输出循环链表
};
class Joseph //    约瑟夫环类
{
private:
    int numOfBoy;  //圈中人数
    int startPosition;  //报数起始点
    int interval;     //报数间隔
public:
    Joseph(int boys, int start, int m) :
        numOfBoy(boys), startPosition(start), interval(m) {}//构造函数
    void setNumOfBoy(int num) { numOfBoy = num; }//重置圈中人数
    void setStartPosition(int start) { startPosition = start; }//重置起始点
    void setInterval(int inter) { interval = inter; }//重置报数间隔
    int GetWinner();//求得最终优胜者编号
    void print();   //输出约瑟夫环
};
template<class T>
CircleLinkList<T>::CircleLinkList(T *d, int  mSize)
{    //构造函数,将d数组中的mSize个元素创建循环链表
//采用前插法创建。
    int i;
    Node<T> *p;
    current = new Node<T>;
    current->data = d[mSize - 1];
    front = current;
    for (i = mSize - 2; i >= 0; i--)
    {
        p = new Node<T>(d[i], current);
        current = p;
    }
    front->link = current;
}
template<class T>
CircleLinkList<T>::~CircleLinkList()    //析构函数
{
    while (current != front)//销毁循环链表
    {
        Node<T> *r = current;
        current = current->link;
        delete r;
    }
    delete current;
}
template<class T>
bool CircleLinkList<T>::InsertAfter(const T&x)
//在current所指结点之后插入x,current指向x结点
{
    Node<T> *s = new Node<T>(x);
    if (!s)return false;
    if (!current)  //原循环链表为空
        current = front = s->link = s;
    else //原循环链表非空
    {
        s->link = current->link;
        current->link = s;
        front = current;
        current = s;
    }
    return true;
}
template<class T>
bool CircleLinkList<T>::RemoveCurrent(T&x) //删除current所指结点
{
    if (!current)//循环链表为空
        return false;
    x = current->data;
    if (current == front)//链表中只有一个元素
    {
        delete current;
        current = front = NULL;
    }
    else
    {
        front->link = current->link;//修改链表指针
        delete current;
        current = front->link;
    }
    return true;
}
template<class T>
void CircleLinkList<T>::Output() const     //输出循环链表
{
    if (!current)//循环链表为空
        return;
    Node<T> *p = current;
    do
    {
        cout << p->data << "  ";
        p = p->link;
    } while (p != current);
    cout << endl;
}
template<class T>
void CircleLinkList<T>::movenext(int k)    //current后移k次
{
    for (int i = 1; i <= k; i++)
    {
        front = current; // front后移
        current = current->link; //current后移
    }
}
template<class T>
bool CircleLinkList<T>::toLocatioin(T &t)
//将current指向元素为t的结点,若没有则current不移动
{
    if (!current)//循环链表为空
        return false;
    Node<T> *current1 = current, *front1 = front;
    while (current1->data != t) //寻找元素t
    {
        front1 = current1;
        current1 = current1->link;
        if (current1 == current)// 已寻找一圈没有元素为t的结点
            return false;
    }
    current = current1; //current指向元素为t的结点
    front = front1;
    return true;
}
int Joseph::GetWinner()//获得最终优胜者
{
    CircleLinkList<int> boys;
    for (int i = 0; i < numOfBoy; i++)//创建循环链表,编号依次为1~numOfBoy
    {
        int temp = i + 1;
        boys.InsertAfter(temp);
    }
    boys.toLocatioin(startPosition);   //找到报数起点
    cout << endl << "依次出列的小孩是:" << endl;
    for (int i = 1; i < numOfBoy; i++)   //numOfBoy-1个小孩出圈
    {
        int x;
        boys.movenext(interval - 1);  //报数
        boys.RemoveCurrent(x); //出圈
        cout << x << "  ";  //输出出圈编号
    }
    return boys.GetCurrentData();  //返回优胜者编号
}
void Joseph::print()   //输出约瑟夫环
{
    cout << "圈中人数:" << numOfBoy << endl;
    cout << "报数起始点:" << startPosition << endl;
    cout << "报数间隔:" << interval << endl;
}

测试代码

//测试代码.cpp
#include"Circle.h"
int main()
{
    int total, interv, startboy;
    cout << "请分别输入人数,起始号码和间隔数"<<endl;
    cin >> total >> startboy >> interv;
    Joseph jose(total, startboy, interv);
    jose.print();
    cout << "优胜者编号为: " << jose.GetWinner() << endl;
    system("pause");
    return 0;
}

原文地址:https://www.cnblogs.com/robotpaul/p/9978017.html

时间: 2024-10-09 20:49:31

【数据结构】1-2 约瑟夫环问题的相关文章

约瑟夫环(N个人围桌,C语言,数据结构)

约瑟夫环问题(C语言.数据结构版) 一.问题描述 N个人围城一桌(首位相连),约定从1报数,报到数为k的人出局,然后下一位又从1开始报,以此类推.最后留下的人获胜.(有很多类似问题,如猴子选代王等等,解法都一样) 二.思路分析 (1)可将人的顺序简单编号,从1到N: (2)构造一个循环链表,可以解决首位相连的问题,同时如果将人的编号改为人名或者其他比较方便 (3)将人的编号插入到结构体的Data域: (4)遍历人的编号,输出参与的人的编号: (5)开始报数,从头报数,报到k的人出局(删除次结点)

约瑟夫环问题,一道经典的数据结构题目

问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数.求胜利者的编号. 一般我们采用一个循环队列来模拟约瑟夫环的求解过程,但是如果n比较大的时候,采用模拟的方式求解,需要大量的时间来模拟退出的过程,而且由于需要占用大量的内存空间来模拟队列中的n个人,并不是一个很好的解法. 在大部分情况下,我们仅仅需要知道最后那个人的编号,而不是要来模拟一个这样的过程,在这种情况下,可以考虑是否存在着一种数学公式能够直接求出最后那个人的编号. 我们知道第一个人(编号

小朋友学数据结构(1):约瑟夫环的链表解法、数组解法和数学公式解法

约瑟夫环的链表解法.数组解法和数学公式解法 约瑟夫环(Josephus)问题是由古罗马的史学家约瑟夫(Josephus)提出的,他参加并记录了公元66-70年犹太人反抗罗马的起义.约瑟夫作为一个将军,设法守住了裘达伯特城达47天之久,在城市沦陷之后,他和40名死硬的将士在附近的一个洞穴中避难.在那里,这些叛乱者表决说"要投降毋宁死".于是,约瑟夫建议每个人轮流杀死他旁边的人,而这个顺序是由抽签决定的.约瑟夫有预谋地抓到了最后一签,并且,作为洞穴中的两个幸存者之一,他说服了他原先的牺牲品

Java数据结构之单向环形链表(解决Josephu约瑟夫环问题)

1.Josephu(约瑟夫.约瑟夫环)问题: 设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列. 提示: 用一个不带头结点的循环链表来处理Josephu 问题:先构成一个有n个结点的单循环链表,然后由k结点起从1开始计数,计到m时,对应结点从链表中删除,然后再从被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除算法

C语言数组实现约瑟夫环问题,以及对其进行时间复杂度分析

尝试表达 本人试着去表达约瑟夫环问题:一群人围成一个圈,作这样的一个游戏,选定一个人作起点以及数数的方向,这个人先数1,到下一个人数2,直到数到游戏规则约定那个数的人,比如是3,数到3的那个人就离开这个游戏:按这样的规则,剩下一个人,游戏就结束,这个人就为赢家.(读者可以试着表达,不认同,直接忽略) 抽象分析 这个人就是一个数据个体,数据结点,数据元素.上面产生的数据结构为:单方向循环的链.可以用链表实现,也可以用数组来实现. 链表到数组的迁移 人(数据元素. 数据结点.数据个体) 结点关系 (

用循环链表解决约瑟夫环的问题

约瑟夫环问题简介 约瑟夫环问题的原来描述为,设有编号为1,2,--,n的n(n>0)个人围成一个圈,从第1个人开始报数,报到m时停止报数,报m的人出圈,再从他的下一个人起重新报数,报到m时停止报数,报m的出圈,--,如此下去,直到所有人全部出圈为止.当任意给定n和m后,设计算法求n个人出圈的次序.  稍微简化一下. 问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数.求胜利者的编号. 解题思路 将每个人的编号作为结点值,因为报数是循环着来的,故可

约瑟夫环-公式递推法

约瑟夫问题 约瑟夫问题是个著名的问题:N个人围成一圈,第一个人从1开始报数,报M的将被杀掉,下一个人接着从1开始报.如此反复,最后剩下一个,求最后的胜利者. 例如只有三个人,把他们叫做A.B.C,他们围成一圈,从A开始报数,假设报2的人被杀掉. 首先A开始报数,他报1.侥幸逃过一劫. 然后轮到B报数,他报2.非常惨,他被杀了 C接着从1开始报数 接着轮到A报数,他报2.也被杀死了. 最终胜利者是C 解决方案 普通解法 刚学数据结构的时候,我们可能用链表的方法去模拟这个过程,N个人看作是N个链表节

一个不简洁的约瑟夫环解法

约瑟夫环类似模型:已知有n个人,每次间隔k个人剔除一个,求最后一个剩余的. 此解法为变种,k最初为k-2,之后每次都加1. 例:n=5,k=3.从1开始,第一次间隔k-2=1,将3剔除,第二次间隔k-1=2,将1剔除.依此类推,直至剩余最后一个元素. 核心思路:将原列表复制多份横向展开,每次根据间隔获取被剔除的元素,同时将此元素存入一个剔除列表中.若被剔除元素不存在于剔除列表,则将其加入,若已存在,则顺势后移至从未加入剔除列表的元素,并将其加入.如此重复n-1次.面试遇到的题,当时只写了思路,没

ytu 1067: 顺序排号(约瑟夫环)

1067: 顺序排号Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 31  Solved: 16[Submit][Status][Web Board] Description 有n人围成一圈,顺序排号.从第1个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来的第几号的那位. Input 初始人数n Output 最后一人的初始编号 Sample Input 3 Sample Output 2 HINT Source freepro