用数组实现约瑟夫环问题

在上一篇中已经介绍了用链表实现约瑟夫环的问题,博文:http://www.cnblogs.com/webor2006/p/7102568.html

其实它还有一种更加简便更加容易理解的实现方式,那就是用数组,当然这两种实现方式的时间复杂度一样,其实现思路跟用链表的基本上类似,下面整理一下:

首先用数组表达一个环,这就没有链表那么麻烦了,还是用四个人围着一个桌子在做淘汰游戏为例:

具体生成的伪代码比较简单:

for(int i = 0; i < 数组长度; i++){
      next_persons[i] = (i + 1) % 数组长度; //为什么要取模,因为最后一个元素得链到第一个元素达到环形的效果
}

所以先把代码框架可以先写好:

接着来整理一下最核心的淘汰逻辑,其实基本上跟用链表实现的思路类似:

这里还是以数3就淘汰的规则来整理【从第一个元素开始数数】:

1、首先判断边界条件:如果数组只剩最后一个元素时,则没必要进行数数了,因为数组不可能为null,不像链表一样,而用代码如何来表示呢?

2、首先数3-1=2下,原因跟链表实现类似,是为了取出真正要淘汰的元素:

3、获得要淘汰的元素next_persons[当前数数的index],并将next_persion[当前数数的index]=next_persion[2]=next_persion[next_persion[当前数数的index]]。

4、在删除index=2之前,有一种特珠情况需要注意,如图:

 

那在删除index=3之前,首先需要将tail指向p,也就是index=2,不然到的把index=3删掉了tail整个状态就不对了,这是需要注意到的。

5、由于是数组,所以不涉及到链表真正的delete操作,只要将其孤立起来既可,不用做任何一些释放的操作。

纵观以上步骤跟链表的实现思路真的大同小异,下面具体看实现代码:

#include<iostream>


class joseph_circle
{
    int* next_persons;//主要是用来记录下一个节点
    int circle_length;//总元素个数
    int tail;//尾结点,默认指向元素最后一位
public:
    joseph_circle(int circle_length): circle_length(circle_length) {
        next_persons = new int[circle_length];
        //生成环形数据
        for (int i = 0; i < circle_length; ++i){
            next_persons[i] = (i + 1) % circle_length;
        }
        tail = circle_length - 1;
    }
    ~joseph_circle() {

    }

    void output() {
        int p = tail;
        while(true){
          p = next_persons[p];
          std::cout << p << " ";      
          if(p == tail)
            break;  //reach the last element of the circle
        }
        std::cout << std::endl;
    }

    //淘汰逻辑的核心方法,动态根据传的值来进行淘汰
    void eliminate(int step) {
        int p = tail;
        while(next_persons[p] != p) {
            //1、首先进行数数,只要step-1既可,因为要在淘汰之前将要淘汰的数据先拿到
            for (int i = 0; i < step - 1; ++i){
                p = next_persons[p];
            }

            //2、将要淘汰的元素孤立起来
            int eliminated_node = next_persons[p];
            next_persons[p] = next_persons[next_persons[p]];

            //3、在淘汰之前需要注意一种特珠情况
            if(eliminated_node == tail) {
                tail = p;
            }

            std::cout << "deleting:" << eliminated_node <<std::endl;
            output();
        }
    }

};

int main(void) {
    
    joseph_circle circle(6);

    circle.eliminate(3);//数到3就淘汰

    return 0;
}

编译运行:

而时间复杂度由于跟用链表实现的一样,所以这里不分析了,具体可以参考上篇博客。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

webor2006

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值