An example of a circular chain representation: solving the Joseph problem

Error: Debug Assertion Failed!

It took a long time to resolve an error in this article today. A code bug is inevitable, but we can optimize and reduce it as much as possible.
Error Analysis: The main reason is that the template class of the circular single-chain list in my previous article was used to solve the problem of Joseph rings, but I did not use the Remove member function in the template class (not because of the limitations of the delete function I defined), but rather
preNode = currNode;
 currNode =currNode->link;
The problem is that the last private member (i.e., the pointer always pointing to the end of a circular single-chain list) is not updated at this time, that is, the last pointer to the node has already been delete d, and when the main function returns, the destructor is called by the systemThe last-pointed node will be released again and errors will occur in the diagram.(This is my analysis result for more than an hour. If something is wrong, I hope Daniel will correct it!).Paste the code below for the error:
 
 
Okay, now paste the whole Joseph problem (including the template classes and the main functions of the circular single-chain list). Joseph rings are an important application of circular single-chain list, and also a very practical problem. I hope everyone can master it. If not, I hope you can make corrections and criticisms!
//Template class

//Circular Chain List Template class
#include <iostream>
using namespace std;

template<class T>
struct CircleLinkNode {
    T data;
    CircleLinkNode<T> *link;
    //Constructor
    CircleLinkNode(CircleLinkNode<T> * next = NULL) : link(next) {}
    CircleLinkNode(T d, CircleLinkNode<T> * next = NULL) : data(d), link(next) {}
};

template<class T>
class CircleList {
public:
    CircleList(const T & x);                        //Constructor
    CircleList(CircleList<T> & L);                  //copy constructor
    ~CircleList();                                 //Destructor
    int Length() const;                             //Calculating the Length of a Circular Chain List
    bool IsEmpty()
    {
        return first->link == first ? true : false; //Determine if it is an empty table?
    }
    CircleLinkNode<T> * getHead() const;            //Returns the address of the additional header node
    void setHead(CircleLinkNode<T> * p);            //Set the address of the additional header node
    CircleLinkNode<T> * Search(T x);                //Search for nodes with data x
    CircleLinkNode<T> * Locate(int i);              //Search for the address of the f i rst element
    T getData(int i);                               //Remove the value of the f i rst element
    void setData(int i, T & x);                     //Modify the value of the first element with
    bool Insert(int i, T & x);                      //Insert x after the f i rst element
    bool Remove(int i, T & x);                      //Delete the ith element and save the deleted data with x
    void createList(T endFlag);                     //Create a single-linked list
    void outputList(int stopSequence);
protected:
    CircleLinkNode<T> *first, *last;                //Head pointer, tail pointer
};

//Function Definition
template<class T>
CircleList<T>::CircleList(const T & x) {
    //Constructor: Open up the header nodes and assign values
    first = new CircleLinkNode<T>(x);
    first->link = first;
    last = first;
} 

template<class T> 
CircleList<T>::~CircleList() {
    //Release corresponding resources
    //if (last != first) {
    //  delete last;
    //}
    delete first;
}

template<class T>
CircleLinkNode<T> * CircleList<T>::getHead() const {
    //Get the function's header pointer
    return first;
}

template<class T>
int CircleList<T>::Length() const {
    //Calculating the length of a chain table
    CircleLinkNode<T> *calculLen = NULL;
    int Len = 0;
    calculLen = first->link;
    while (calculLen != first) {                    //Returns the length of the count when loop to first again
        Len++;
        calculLen = calculLen->link;
    }
    return Len;
}

template<class T>
CircleList<T>::CircleList(CircleList<T> &L) {
    //copy constructor
    int Len = Length();                             //Get the length of the current list
    CircleLinkNode<T> *create = NULL, *destData, *srcData;
    create = new CircleLinkNode<T>(0);
    if (!create) {
        cerr << "memory alloc error" << endl;
        exit(1);
    }
    last = create;                                  //Tag tail node
    for (int i = 0; i < Len - 1; i ++) {
        create->link = first->link;
        first->link = create;
        create = new CircleLinkNode<T>(0);
        if (!create) {
            cerr << "memory alloc error" << endl;
            exit(1);
        }
    }
    //copy data fields from L to the current list one by one
    copyData = first->link;
    srcData = L.first->link;
    while (srcData == L.first) {
        destData->data = srcData->data;
        destData = destData->link;
        srcData = srcData->link;
    }
    //Building a circular chain table
    last->link = first;
}

template<class T>
CircleLinkNode<T> * CircleList<T>::Search(T x) {
    //Find a node whose data field is x and return its address
    CircleLinkNode<T> * current = NULL;
    current = first->link;
    while (current != first) {
        if (current->data == x) {
            break;
        }
        current = current->link;
    }
    return current;
}

template<class T>
CircleLinkNode<T> * CircleList<T>::Locate(int i) {
    //Location function that returns the address of the ith node for insertion and deletion functions
    if (i < 0 || i > Length()) {
        cout << "Illegal data" << endl;
        cin >> i;
        return NULL;
    }
    CircleLinkNode<T> * current = NULL;
    current = first;
    for (int j = 0; j < i; j ++) {
        current = current->link;
    }
    return current;
}

template<class T>
void CircleList<T>::createList(T endFlag) {
    //Create single-chain list in reverse order
    T inputData = 0;
    CircleLinkNode<T> *create = NULL;
    cin >> inputData;
    create = new CircleLinkNode<T>(inputData);      //Create a tail node outside the loop
    if (!create) {
        cerr << "memory alloc error" << endl;
        exit(1);
    }
    last = create;                                  //Tag tail node
    while (inputData != endFlag) {                  //Whether the end condition is met
        create->link = first->link;                 //Establish links
        first->link = create;
        cin >> inputData;
        create = new CircleLinkNode<T>(inputData);  //Build other nodes in turn
        if (!create) {
            cerr << "memory alloc error" << endl;
            exit(1);
        }
    }
    //Single Chain List Establishment Completed
    last->link = first;                             //Building a circular chain table
}

template<class T>
T CircleList<T>::getData(int i) {
    CircleLinkNode<T> * current;
    current = Locate(i);                            //Locate function calls
    return current->data;
}

template<class T>
void CircleList<T>::setData(int i, T & x) {
    //Set the data field of the ith node to x
    CircleLinkNode<T> * current = NULL;
    current = Locate(i);
    current->data = x;                              //Complete Modification
}

template<class T>
bool CircleList<T>::Insert(int i, T & x) {
    //Insert a new node after the first node and assign its data field to x
    CircleLinkNode<T> * flagPtr;
    CircleLinkNode<T> * newNode = new CircleLinkNode<T>(x);
    if (!newNode) {                                 //memory alloc error
        return false;
    }
    if (0 == i) {                                   //Insert at the top
        newNode->link = first->link;
        first->link = newNode;
    }
    else {
        flagPtr = Locate(i);
        newNode->link = flagPtr->link;
        flagPtr->link = newNode;
    }
    //Update last-pointed node
    last = Locate(Length());
    return true;
}

template<class T>
bool CircleList<T>::Remove(int i, T & x) {
    //Delete the ith node and store the deleted data in x
    CircleLinkNode<T> *preNode = NULL, *delNode = NULL;
    preNode = Locate(i - 1);
    delNode = Locate(i);
    preNode->link = delNode->link;
    delete delNode;
    return true;
}

template<class T>
void CircleList<T>::outputList(int stopSequence) {
    if (first == first->link) {
        cout << "This is an empty table" << endl;
        return;
    }
    //Output loop list until specified sequence number stops output (easy to test loop characteristics)
    CircleLinkNode<T> * current = NULL;
    current = first->link;
    for (int i = 0; i < stopSequence; i ++) {
        cout << current->data << " ";
        current = current->link;
        if (current == first) {
            current = current->link;                //Skip first output
        }
    }
    cout << endl;
}

Main Function and Joseph Processing Function Test

//An example of a circular chain table to solve the Joseph problem
#include <iostream>
#include "CircleList.cpp"
using namespace std;
template<class T>
void Josephus(CircleList<T> & js, int n, int m);
int main()
{
    CircleList<int> circle(0);
    int nodesAmount = 0, delSequence = 0, data = 0, sotre;
    cout << "Enter the number of players and the number of reports interval:" << endl;
    cin >> nodesAmount >> delSequence; 
    for (int i = 0; i < nodesAmount; i ++) {                    //Form Joseph rings
        data = i + 1;
        circle.Insert(i, data);
    }
    Josephus(circle, nodesAmount, delSequence);                 //Solve the Joseph problem

    system("pause");
    return 0;
} 
template<class T>
void Josephus(CircleList<T> & js, int n, int m) {
    //To solve the Joseph problem
    //Parameters: Circular Chain List, Number of Nodes, Delete Interval of Nodes
    CircleLinkNode<T> *preNode = NULL, *currNode = NULL;        //Define two flag nodes
    preNode = js.getHead();
    currNode = preNode->link;
    for (int i = 0; i < n - 1; i ++) {                          //Loop n - once, with only one node left
        for (int j = 0; j < m - 1; j ++) {                      //One report cycle at a time
            if (currNode == js.getHead()) {
                preNode = currNode;
                currNode = currNode->link; 
            }
            //Start deleting node after message count
            preNode = currNode;
            currNode = currNode->link;
            if(currNode == js.getHead()) {
                preNode = currNode;
                currNode = currNode->link;
            }
        }
        cout << "The data deleted is: " << currNode->data << endl;
        preNode->link = currNode->link;
        delete currNode;
        currNode = preNode->link;                               //Don't miss this step
    }
}  

The results of normal operation show that:
Data structure needs a lot of time to practice and research, I hope we can spend more time to practice, cherish the current time, and do anything with a goal!

Added by codects on Mon, 20 May 2019 20:44:52 +0300