约瑟夫环问题

Josephu 问题为:设编号为1,2,…,n的n个人围坐一圈,约定编号为k(1≤k≤n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,以此类推,直到所有人出列为止,由此产生一个出队编号的序列。

Josephu问题可以用一个不带头结点的循环链表解决。请编写算法,先构成一个有n个结点的不带头结点的循环链表,然后由k结点起从1开始计数,计到m时,对应结点从链表中删除,然后被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除时算法结束。

 新定义的不带头结点的循环链表如下:

#include "CList.h"

template 
class CListX : public List
{
public:
    //构造函数
    CListX() { this->header->next = this->header; }

    ~CListX() //析构函数
    {
        get_node(this->_size)->next = NULL; //还原成单链表
    }

    LNode *get_header() { return this->header; }

    LNode *get_node(int i)
    {
        int j = 1;
        LNode *p = this->header;
        while (p->next != this->header && j < i)
        {
            p = p->next;
            ++j;
        }
        if (!p || j != i)   return NULL;
        else    return p;
    }

    int locate_elem(T e)
    {
        LNode *p = this->header;
        for (int i = 1; p; p = p->next, i++)
            if (p->data == e)    return i;
        return 0;
    }

    void insert(T const &e)
    {
        LNode *p = this->header;
        LNode *q;
        if (this->empty())   p->data = e;
        else
        {
            q = new LNode();
            q->data = e;
            get_node(this->_size)->next = q;
            q->next = p;
        }
        this->_size++;
        return;
    }

    T remove(LNode *p)
    {
        T e = p->data; //备份删除结点数值
        LNode *q;
        //找到前一个结点的位置
        int location = locate_elem(e) - 1; 
        //处理前一个结点不是最后一个结点
        if (location)  q = get_node(location);
        //处理前一个结点结点是最后一个结点
        else    q = get_node(this->_size);
        //处理删除结点是头结点
        if (p == this->header)   this->header = p->next;
        q->next = p->next;
        this->_size--;
        delete p; // 删除并释放结点
        return e;
    }
};

 定义文件中的主程序如下:

#include "CListX.h"
#include 

using namespace std;

//创建不带头结点的循环链表
void creat_CListX(CListX &L)
{
    cout << "请顺序输入链表元素Ctrl+Z结束,"
         << "建立带头结点的链表:\n";
    int x;
    while (cin >> x)  L.insert(x); //按Ctrl+Z组合键结束输入
    cin.clear();     // 更改cin的状态标示符
    rewind(stdin);   //清空输入缓存区
}

//打印不带头结点的循环链表
void print_CListX(CListX &L)
{
    if (L.empty())
    {
        cout << "双向链表为空!\n";
        return;
    }
    LNode *p = L.get_header();
    cout << "双向链表共有" << L.size() << "个元素:\n";
    while (p->next != L.get_header())
    {
        cout << p->data << ' ';
        p = p->next;
    }
    cout << p->data << "\n";
    cout << endl;
}

//解决参数为k、m的josephu问题
void josephu(int k, int m, CListX &L)
{
    LNode *p = L.get_node(k + m);
    cout << "josephu问题出队编号的序列为:" << endl;
    while (L.size() > 1)
    {
        cout << p->data << ' ';
        L.remove(p);
        int i = 1;
        while (i <= m)
        {
            p = p->next;
            ++i;
        }
    }
    cout << L.get_header()->data;
    cout << endl;
}

int main()
{
    CListX L;
    creat_CListX(L);
    print_CListX(L);
    josephu(2, 3, L);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值