Search code examples
c++circular-list

Can I use a while or for loop to print the list?


#include <iostream>
#include <string.h>

namespace  forward_circular_linked_list {
    typedef struct Node {
        std::string data;
        Node *nextNode;
    }Node;

    class ForwardCircularLinkedList {
    private:
        Node *head;

    public:
        ForwardCircularLinkedList() : head(nullptr) {}

        void AddItem(std::string data) {
            Node * newNode = new Node();
            newNode->data = data;

            if(head == nullptr)
            {
                head = newNode;
                newNode->nextNode = head;
            } else{
                Node * copyOfHead = head;
                while(copyOfHead->nextNode != head)
                {
                    copyOfHead = copyOfHead->nextNode;
                }
                copyOfHead->nextNode = newNode;// process last node
                newNode->nextNode = head;
            }
        }
        void print()
        {
            Node * copyOfHead = head;

            do
            {
                std::cout<<copyOfHead->data;
                copyOfHead = copyOfHead->nextNode;
            }while(copyOfHead != head);
        }

    public:
        static void Test() {
            ForwardCircularLinkedList list;
            list.AddItem("Hello");
            list.AddItem(" ");
            list.AddItem("World");
            list.AddItem("!");
            list.print();
        }
    };
}

here, a do-while is being used to print the elements of the list.

At the current setup, Can I use a while or for loop to print the list?

Note: I am considering do-while and while as different looping structures.


Solution

  • Yes, you can use do-while or a for loop. But do-while is more natural because it checks the condition after the body of code.

    You have a circular data structure and (presumably) you want to print each element once. Doing only one round of circling. do{...move circulator}while(compare with head) has the right logic.

    CGAL implements "circulators" and does exactly that, it starts from "head" does something and increments the circulator until it is head once again. See https://doc.cgal.org/latest/Circulator/classCirculator.html (scroll to Example).

    Note the example also checks for emptyness at start, but probably you want. (In my mind a circular buffer is never empty, but I accept other opinions.)


    With while you have:

            Node * copyOfHead = head;
    
            do
            {
                std::cout<<copyOfHead->data;
                copyOfHead = copyOfHead->nextNode;
            }while(copyOfHead != head);
    

    With for you can have

            Node * copyOfHead = head;
    
            for(;;){
                std::cout<<copyOfHead->data;
                copyOfHead = copyOfHead->nextNode;
                if(copyOfHead == head) break;
            }
    

    or

            for(Node * copyOfHead = head;;){
                std::cout<<copyOfHead->data;
                copyOfHead = copyOfHead->nextNode;
                if(copyOfHead == head) break;
            }
    

    or

            for(Node * copyOfHead = head; ; copyOfHead = copyOfHead->nextNode){
                std::cout<<copyOfHead->data;
                if(copyOfHead->nextNode == head) break;
            }
    

    or (exploiting that the body of the loop evaluates to bool:true)

            for(
                Node * copyOfHead = head;
                std::cout<<copyOfHead->data;
                copyOfHead = copyOfHead->nextNode
            ) if(copyOfHead->nextNode == head) break;
    

    The main advantage of for is the initialization, but still it is not worth it. You can of course do the step outside the loop but then you have repeated code, etc.

    (NOT RECOMMENDED, it may even have a bug)

            Node * copyOfHead = head;
            std::cout<<copyOfHead->data;
            copyOfHead = copyOfHead->nextNode;
    
            for(; copyOfHead != head ;copyOfHead = copyOfHead->nextNode){
                std::cout<<copyOfHead->data;
            }
    

    So, there you have, do-while is exactly what you want for this kind of data structure! and for (or while-only) is exactly what you don't want.