Link to home
Start Free TrialLog in
Avatar of ECUBlake
ECUBlake

asked on

creating a copy constructor for a circluar linked list

I am working on a program that will simulate the Josephus problem.  My problem comes in when I need to create the copy constructor.  I cannot see how to copy all the private members in my class as well as all the nodes in the original list.

My class is:
#ifndef CIRCLINKEDLIST_H
#define CIRCLINKEDLIST_H
#include "CIRCLINKEDLIST.H"

typedef struct node* NodePtr;
typedef char NodeItemType;

struct node
{
    NodeItemType item;
    NodePtr next;
};


class CircleLL
{
public:
    CircleLL();
    ~CircleLL();
    CircleLL(const CircleLL& objtocopy);
    void operator= (const CircleLL& rightside);

    void insert(const NodeItemType& newItem, bool& success);
    //inserts a new node at last position.  newItem is the data to insert

    void remove(int index, bool& success);
    //removes node at index number.  index is the number to jump by

    NodeItemType retrieve(int index, bool& success);
    //retuns the specified item type at the index number in the list
    //if index is 3, the 3rd item in the list will be returned

    bool isEmpty();
    //returns true if the list is empty

    int getLength();
    //returns the number of nodes in the list

    void curPosition(int& index);
    //moves cur pointer to the desired index position


private:

    NodePtr head;
    //head pointer(doesn't move)

    NodePtr cur;
    //cur points to the current node you
    //want to access

    int size;
    //size of the circle linked list

};

Please help if you can, and if more information is needed please tell me.
Avatar of n_fortynine
n_fortynine

>> I cannot see how to copy all the private members in my >> class as well as all the nodes in the original list.
What *part* can you not see how? Btw some code would be helpful.
Avatar of ECUBlake

ASKER

Here is the code for the class. If I insert 5 nodes to my list, I need to be able to copy all five nodes and the anything else in the class.

//circlinkedlist.cpp

CircleLL::CircleLL():size(0), head(NULL)
{
    cur = head;
}

void CircleLL::insert (const itemtype& NewItem, bool& success)
{
         if(head == NULL)                      //insert to empty list
         {
             NodePtr temp = new node;
             temp->next=temp;
             temp->item=NewItem;
             head=temp;
         }
         else
         {    cur = head;
              do
              {
                  cur = cur->next;
              }while(cur->next != head);

              NodePtr temp = new node;
              cur->next = temp;
              temp->item = NewItem;
              temp->next = head;
         }

     size++;
     success = true;
}


void CircleLL::remove(int index, bool& success)
{
    NodePtr prev = head;
    NodePtr killptr = cur;

    while(prev->next != killptr)
    {
         prev = prev->next;
    }
    cerr << "Kill   : " << killptr->item << endl;
    if(killptr == head)                 //delete head node
    {
         prev->next = head;
         cur = cur->next;
         killptr->next = NULL;
         delete killptr;
    }

    else                                      //delete all other nodes
    {
         prev->next = killptr->next;
         cur = cur->next;                     //update cur pointer to point to
         killptr->next = NULL;                //next "alive" node
         delete killptr;
    }
    cerr << "current: " << cur->item << endl;
    size--;
}

NodeItemType CircleLL::retrieve(int index, bool& success)
{
    curPosition(index);              //return item of the current node

    return cur->item;
}

bool CircleLL::isEmpty ()
{
    return bool(size == 0);
}

int CircleLL::getLength()
{
    return size;
}

void CircleLL::curPosition(int& index)
{
    for(int count = 1; count < index; ++count)         //transverse list to jump
        cur = cur->next;                               //number
}


#endif
I think this will work, please verify I have to go to class:
CircleLL::CircleLL(const CircleLL& obj) : head(NULL), cur(NULL), size(obj.size) {
   if(size) {
      NodePtr tmp = obj.head;
      cur = new node;
      cur->item = tmp->item;
      tmp = tmp->next;
      head = cur;

      while(size - 1) {
         cur->next = new node;
         cur = cur->next;
         cur->item = tmp->item;
         tmp = tmp->next;
      }

      tmp = NULL;
      cur->next = head;
      cur = head;
   }
}
>> while(size - 1) changes too while(--size) then add the size = obj.size to the end of this. sorry i wrote in a hurry.
its still not copying right, my input has duplicates of some info.  big help though, at least something is printing out now.  but i know for sure my insert function is working correctly, and the program crashes most likely because of pointer errors while copying.
I think this whole piece works for me, what i changed was I reset cur to head at the beginning of retrieve. You HAVE TO write the destructor. I compiled this on UNIX GCC.

#ifndef CIRCLINKEDLIST_H
#define CIRCLINKEDLIST_H

#include <stddef.h>
#include <errno.h>
#include <iostream.h>

typedef struct node* NodePtr;
typedef char NodeItemType;

struct node {
   NodeItemType item;
   NodePtr next;
};

class CircleLL {
   public:
      CircleLL();
      ~CircleLL() {}
      CircleLL(const CircleLL& objtocopy);
      void operator= (const CircleLL& rightside);
      void insert(const NodeItemType& newItem, bool& success);
      void remove(int index, bool& success);
      NodeItemType retrieve(int index, bool& success);
      bool isEmpty();
      int getLength();
      void curPosition(int& index);

   private:
      NodePtr head;
      NodePtr cur;
      int size;
};

#endif

CircleLL::CircleLL() : size(0), head(NULL), cur(head) {}

void CircleLL::insert(const NodeItemType& NewItem, bool& success) {
   if(!head) {
      NodePtr temp = new node;
      temp->next = temp;
      temp->item = NewItem;
      head = temp;
   }
   else {
      cur = head;
      do { cur = cur->next; } while(cur->next != head);
      NodePtr temp = new node;
      cur->next = temp;
      temp->item = NewItem;
      temp->next = head;
   }

   size++;
   success = true;
}

void CircleLL::remove(int index, bool& success) {
   NodePtr prev = head;
   NodePtr killptr = cur;

   while(prev->next != killptr) { prev = prev->next; }
   cerr << "Kill   : " << killptr->item << endl;
   if(killptr == head) {
      prev->next = head;
      cur = cur->next;
      killptr->next = NULL;
      delete killptr;
   }
   else {
      prev->next = killptr->next;
      cur = cur->next;                     //update cur pointer to point to
      killptr->next = NULL;                //next "alive" node
      delete killptr;
   }

   cerr << "current: " << cur->item << endl;
   size--;
}

NodeItemType CircleLL::retrieve(int index, bool& success) {
   cur = head;
   curPosition(index);
   return cur->item;
}

bool CircleLL::isEmpty () { return !size; }

int CircleLL::getLength() { return size; }

void CircleLL::curPosition(int& index) {
   for(int count = 1; count < index; ++count)
       cur = cur->next;
}

CircleLL::CircleLL(const CircleLL& obj) : head(NULL), cur(NULL), size(obj.size) {
  if(size) {
     NodePtr tmp = obj.head;
     cur = new node;
     cur->item = tmp->item;
     tmp = tmp->next;
     head = cur;

     while(--size) {
        cur->next = new node;
        cur = cur->next;
        cur->item = tmp->item;
        tmp = tmp->next;
     }

     tmp = NULL;
     cur->next = head;
     cur = head;
     size = obj.size;
  }
}

int main() {
   CircleLL L1;
   bool s;
   L1.insert('a', s);
   L1.insert('b', s);
   cout << s << "\n";
   CircleLL L2(L1);
   cout << L2.retrieve(1, s) << L2.retrieve(2, s);
}

You put this all in one .cpp file and test it, change the main() to your main() if you want, let me know how it turns out. I need to go to class again. =)
you might want to test the sensitive cases (copy empty lists, copy one item lists etc. and test your delete cos I didn't test it)
haha... I'm almost completely stumped... and my professor doesn't have office hours today. after this is solved, or if it does i'll increase points to 75 (thats all i have :) ) but below is a copy of my main.  what i need to do is move around the circle and "kill" a node at index position, then move to the next "alive" node then jump index nodes and "kill" that one until there is one left.
i really appricate the help.

#include <fstream.h>
#include <iostream.h>
#include <stdlib.h>
#include "CIRCLINKEDLIST.H"

void display(CircleLL y, bool& success)
{
    NodeItemType data;

    cout << "          size=" <<y.getLength() << "  (";
    for(int count = 1; count <= y.getLength(); count++)
    {
        data = y.retrieve(count, success);
        cout << data << ", ";
    }
    cout << ")" << endl;
}


void main()
{
     NodeItemType newitem;
     bool success;

     CircleLL x;

     char filename[30];
     ifstream infile;

     int index=0;
     cout << "Enter number of jumps: ";
     cin >> index;

     cout << "Enter the file name: ";
     cin >> filename;

     infile.open(filename);          //check for vaild file name
     if(infile.fail())
     {
         cout << "Error: No such file name." << endl;
         system("PAUSE");
         exit(1);
     }

     NodeItemType data;

     while(infile >> data)                //get all data from file
     {
         x.insert(data, success);
     }
     cout << "Starting length is: " << x.getLength() << endl;

     display(x, success);
     cout << endl;

     while(x.getLength() > 1)
     {
        x.remove(index, success);
        x.curPosition(index);
        display(x, success);
     }

     system("PAUSE");
}
Here's a solution for this problem from a non-OO POV you can have a look at. I still have one last class so I can't help much till I'm back.

//@Description: Solving the Joshua Death's Problem
//              Starting from 1, count circularly to M then that person kills himself.
#include <iostream.h>

struct node {
   int key;
   node *next;
};

int main() {
   int i, M, N;                 //M < N.
   node *t, *x;

   cout << "Enter them now: \n";
   cin >> N >> M;

   t = new node;
   t -> key = 1;                //Insert first item.
   x = t;                       //x is now "head."

   for(i = 2; i <= N; ++i) {
      t -> next = new node;
      t = t -> next;
      t -> key = i;
   }                            //Finish inserting items from 1 to N.

   t -> next = x;               //Circular list.

   while(t != t -> next) {      //While there ain't only 1 node
      for(i = 1; i < M; ++i)    //Traverse M positions
         t = t -> next;
      cout << t -> next -> key << " ";
      x = t -> next;
      t -> next = x -> next;
      delete x;
   }

   cout << t -> key << " ";
}
N is the number of people and M is the number of jumps
There's a problem with your remove(). int index is not used and really shouldn't be there. I gotta go to class.
ok i won't. could you explain more to me what remove() is supposed to do?
remove() "kills" or takes a node out of the list.
yeah but what does index do. So if I do remove(3,success) then the 3rd node gets removed then? Ok.
remove() "kills" or takes a node out of the list.
remove() "kills" or takes a node out of the list.
ASKER CERTIFIED SOLUTION
Avatar of n_fortynine
n_fortynine

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
wow.... don't i feel dumb :)  you're right the order of the remove() and traverse function made a big difference, and now there are no more errors.  I can't thank you enough
big help and very fast responses