约瑟夫环(循环链表解法)

约瑟夫环的问题大家不陌生了吧,在n个人中循环喊口号1~m,喊到m的退出,求退出次序。

首先,循环链表的类可以这么实现(已略去与本题不相关的成员函数):
如需查看完整循环链表类实现,请参考我的GitHub:循环链表完整类

//所有下标均从1开始计数
template<class T>
class CircleList {
protected:
    int n;
    node<T>* head;
    node<T>* tail;
    node<T>* ptr;  //这里为什么需要一个ptr指针呢? 因为删除操作有了这个更好操作,删除到哪,ptr就指到哪。
public:
    CircleList():n(0) {init();ptr=head;}  //构造函数, 结点数初始化为0
    void init() {  //初始化链表
        head = new node<T>;
        head->next = head;
        head->last = head;
        tail = head;
    }
    void Delete(int pos) {  //删除结点
        while(pos--) {
            baby=baby->next;  
            if(baby == head)  pos++;  //头结点需要特殊处理一下,不算在pos位移之内
        }
        ptr->last->next = ptr->next;
        ptr->next->last = ptr->last;
        node<T>* tmp = ptr->last;  //临时储存ptr的上一个节点,以便下次使用
        delete ptr;
        ptr=tmp;
        n--;
    }
    T At(int pos) {  //查询pos位置上的值
        node<T>* tmp=ptr;  //拷贝一个ptr的副本,因为我们是输出该位置上的数值之后删除,如果输出的时候动了ptr指针,等下删除没法正常进行
        while(pos--) {
            tmp=tmp->next;
            if(tmp==head)  pos++;
        }
        return tmp->data;
    }
    bool is_Empty() {return n == 0;}
    ~CircleList() {  //析构函数
        node<T>* p=head->next;
        node<T>* q;
        while(p != head) {
            q=p->next;
            delete p;
            p=q;
        }
        delete head;
        n = 0;
    }
};

设计好了一个恰当的类,将对主函数实现起到莫大的作用:

//简短的主函数
int main() {
    int n,m;
    cin>>n>>m;
    CircleList<int> v;
    for(int i=1;i<=n;i++)  v.push(i);
    int cnt=1;
    while(!v.is_Empty()) {
        if(cnt==m+1) cnt=1;
        if(cnt == m) {
            cout<<v.At(cnt)<<" ";
            v.Delete(cnt);
        }
        cnt++;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值