算法----约瑟夫环的简易实现

题目:用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出。

分析:该题目的通用解法是利用循环链表,当然也可以利用循环数组。易于扩展的做法是,定义循环链表的数据结构,并实现循环链表的基本操作,利用这些基本操作如插入、删除、初始化、构建链表等操作;简易的实现方法则是仅适合该题目的解法。

采用无头的循环链表,如果有头,则需要在每次遍历中跳过头节点。因为采用了无头的链表,因此在插入或者删除时,需要针对头节点特殊处理:

1、插入时,链表为空,则当前待插入的节点为链表头;

2、删除时,由于题目只要求输出删除节点,链表又是循环链表,因此可以不考虑删除节点为头节点的情况。不过,为了删除当前节点,我们需要保存其前驱结点的指针。

代码如下:

#include <iostream>
#include "joseph.h"

using namespace std;

void joseph()
{
    int m = 0, n = 0;
    cin >> n >> m;

    Node head = NULL;
    Node current = NULL;

    for (int i = 1; i <= n; ++i) {
        Node tempNode = new ListNode();
        tempNode->data = i;

        if (head == NULL) {              //构建链表,特殊处理头节点
            head = tempNode;
            head->next = head;
            current = head;
        } else {
            current->next = tempNode;
            tempNode->next = head;
            current = current->next;
        }
    }

    Node prev = current;            //此处有些取巧,我们从链表头开始遍历链表,其前驱应为表尾,链表构建完成过后current指针恰好为表尾,因此先保存该指针
    current = head;                    //再给current赋值,指向表头
    int cnt = 1;                            //初始化计数器,当前节点计数器为1

    while (current != current->next) { //循环条件为直至链表剩余一个元素,此时current != current->next
        if (cnt == m) {
            cnt = 1;                         //当前节点需要删除,重置计数器
            prev->next = current->next;         //更改当前节点的前驱结点的后继结点为当前节点的后继
            cout << current->data << '\t';
            delete current;
            current = prev->next;     //重新赋值current
        } else {
            ++cnt;
            prev = current;
            current = current->next;
        }
    }

    cout << current->data << endl;        //输出链表最后一个元素
    delete current;

}
    原文作者:约瑟夫环问题
    原文地址: https://blog.csdn.net/Ainiybs/article/details/37652833
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞