简体   繁体   中英

C++ Split a LinkedList into 2 and destroy input List

From a C++ beginner. I wrote a method (below) that splits the input list into 2 other lists and leave original unchanged (it works), I need a new method "split" that destroys the input chain ∗this and uses its nodes to construct the chains a and b. my attempts to delete the original chain has been unsuccessful. Thanks in advance.

// Split A into two chains B and C.
// When done, A is unchanged.
template <class T>
void chain<T>split(chain<T>& A, chain<T>& B, chain<T>& C)
{
    // first free all nodes in B and C

    int j;
    j=0 ;
    listSize = B.listSize;
    for (j=0 ; j < listSize; j++)
        B.erase(0);

    // C.Erase();
    j=0 ;
    listSize = C.listSize;
    for (j=0 ; j < listSize; j++)
        C.erase(0);


    // assign elements alternately to B and C
    int n=0;
    chain<T>::iterator a = A.begin(); // find first node of A
    while (a != A.end()) {
        // first give B an element
        B.insert(n,*a);
        a++;

        if (a == A.end()) break;
        // now give C an element
        C.insert(n,*a);
        a++;
        n=n+1;
    }
}

    #ifndef chain_
    #define chain_
    #include "linearList.h"
    #include "chainNode.h"

    using namespace std;
    template<class T>

    class linkedDigraph;
    template <class T> class linkedWDigraph;

    template<class T>
    class chain : public linearList<T> 
    {
       friend linkedDigraph;
       friend linkedWDigraph<int>;
       friend linkedWDigraph<float>;
       friend linkedWDigraph<double>;


       public:
          // constructor, copy constructor and destructor
          chain(int initialCapacity = 10);
          chain(const chain<T>&);
          ~chain();

          // ADT methods
          bool empty() const {return listSize == 0;}
          int size() const {return listSize;}
          T& get(int theIndex) const;
          int indexOf(const T& theElement) const;
          void erase(int theIndex);
        void Split(chain<T>& A, chain<T>& B, chain<T>& C);

              //Operator []
          typedef int size_type;



            // iterators to start and end of list
          class iterator;
          iterator begin() {return iterator(firstNode);}
          iterator end() {return iterator(NULL);}

          // iterator for chain
          class iterator 
          {
             public:
                // typedefs required by C++ for a forward iterator
                typedef forward_iterator_tag iterator_category;
                typedef T value_type;
                typedef ptrdiff_t difference_type;
                typedef T* pointer;
                typedef T& reference;

                // constructor
                iterator(chainNode<T>* theNode = NULL)
                   {node = theNode;}

                // dereferencing operators
                T& operator*() const {return node->element;}
                T* operator->() const {return &node->element;}

                // increment
                iterator& operator++()   // preincrement
                         {node = node->next; return *this;}
                iterator operator++(int) // postincrement
                          {iterator old = *this;
                           node = node->next;
                           return old;
                          }


                // equality testing
                bool operator!=(const iterator right) const
                      {return node != right.node;}
                bool operator==(const iterator right) const
                      {return node == right.node;}
             protected:
                chainNode<T>* node;

          };  // end of iterator class


       //Overload []
         T& operator[](size_type index) 
            { 

                return element[index]; 
            }

       const T& operator[](size_type index) const
            {

                return element[index];
            }


       protected:
          void checkIndex(int theIndex) const;
                // throw illegalIndex if theIndex invalid
          chainNode<T>* firstNode;  // pointer to first node in chain
          int listSize;             // number of elements in list
    };

    template<class T>
    chain<T>::chain(int initialCapacity)
    {// Constructor.
       if (initialCapacity < 1)
       {ostringstream s;
        s << "Initial capacity = " << initialCapacity << " Must be > 0";
        throw illegalParameterValue(s.str());
       }
       firstNode = NULL;
       listSize = 0;
    }

    template<class T>
    chain<T>::chain(const chain<T>& theList)
    {// Copy constructor.
       listSize = theList.listSize;

       if (listSize == 0)
       {// theList is empty
          firstNode = NULL;
          return;
       }

       // non-empty list
       chainNode<T>* sourceNode = theList.firstNode;
                        // node in theList to copy from
       firstNode = new chainNode<T>(sourceNode->element);
                        // copy first element of theList
       sourceNode = sourceNode->next;
       chainNode<T>* targetNode = firstNode;
                        // current last node in *this
       while (sourceNode != NULL)
       {// copy remaining elements
          targetNode->next = new chainNode<T>(sourceNode->element);
          targetNode = targetNode->next;
          sourceNode = sourceNode->next;
       }
       targetNode->next = NULL; // end the chain
    }

    template<class T>
    chain<T>::~chain()
    {// Chain destructor. Delete all nodes in chain.
       while (firstNode != NULL)
       {// delete firstNode
          chainNode<T>* nextNode = firstNode->next;
          delete firstNode;
          firstNode = nextNode;
       }
    }

    template<class T>
    void chain<T>::checkIndex(int theIndex) const
    {// Verify that theIndex is between 0 and listSize - 1.
       if (theIndex < 0 || theIndex >= listSize)
       {ostringstream s;
        s << "index = " << theIndex << " size = " << listSize;
        throw illegalIndex(s.str());
       }

    }

    template<class T>
    T& chain<T>::get(int theIndex) const
    {// Return element whose index is theIndex.
     // Throw illegalIndex exception if no such element.
       checkIndex(theIndex);

       // move to desired node
       chainNode<T>* currentNode = firstNode;
       for (int i = 0; i < theIndex; i++)
          currentNode = currentNode->next;

       return currentNode->element;
    }

    template<class T>
    int chain<T>::indexOf(const T& theElement) const
    {// Return index of first occurrence of theElement.
     // Return -1 if theElement not in list.

       // search the chain for theElement
       chainNode<T>* currentNode = firstNode;
       int index = 0;  // index of currentNode
       while (currentNode != NULL && 
              currentNode->element != theElement)
       {
          // move to next node
          currentNode = currentNode->next;
          index++;
       }

       // make sure we found matching element
       if (currentNode == NULL)
          return -1;
       else
          return index;
    }

    template<class T>
    void chain<T>::erase(int theIndex)
    {// Delete the element whose index is theIndex.
     // Throw illegalIndex exception if no such element.
       checkIndex(theIndex);

       // valid index, locate node with element to delete
       chainNode<T>* deleteNode;
       if (theIndex == 0)
       {// remove first node from chain
          deleteNode = firstNode;
          firstNode = firstNode->next;
       }
       else 
       {  // use p to get to predecessor of desired node
          chainNode<T>* p = firstNode;
          for (int i = 0; i < theIndex - 1; i++)
             p = p->next;

          deleteNode = p->next;
          p->next = p->next->next; // remove deleteNode from chain
       }
       listSize--;
       delete deleteNode;
    }

    template<class T>
    void chain<T>::insert(int theIndex, const T& theElement)
    {// Insert theElement so that its index is theIndex.
       if (theIndex < 0 || theIndex > listSize)
       {// invalid index
          ostringstream s;
          s << "index = " << theIndex << " size = " << listSize;
          throw illegalIndex(s.str());
       }

       if (theIndex == 0)
          // insert at front
          firstNode = new chainNode<T>(theElement, firstNode);
       else
       {  // find predecessor of new element
          chainNode<T>* p = firstNode;
          for (int i = 0; i < theIndex - 1; i++)
             p = p->next;

          // insert after p
          p->next = new chainNode<T>(theElement, p->next);
       }
       listSize++;
    }



    template <class T>
    void chain<T>::Split(chain<T>& A, chain<T>& B, chain<T>& C)

    {// Split A into two chains B and C.

     // When done, A is unchanged.

       // first free all nodes in B and C

         // find firt node of A

     //  B.erase();
        int j;
        j=0 ;
        listSize = B.listSize;
       for (j=0 ; j < listSize; j++)
           B.erase(0);

      // C.Erase();
       j=0 ;
        listSize = C.listSize;
       for (j=0 ; j < listSize; j++)
           C.erase(0);

        for (chain<T>::iterator b = A.begin();
            b != A.end(); b++)
          cout << "A from in " << *b << "  ";

       // assign elements alternately to B and C
       int n=0;
       chain<T>::iterator a = A.begin();
       chainNode<T>  *current;

         while (a != A.end()) {
             B.insert(n,*a);// first give B an element
             a++;

          if (a == A.end()) break;
               C.insert(n,*a); // now give C an element

           a++;
           n=n+1;
           }

    }



    // chain node

    #ifndef chainNode_
    #define chainNode_

    template <class T>
    struct chainNode 
    {
       // data members
       T element;//data 
       chainNode<T> *next;//link

       // methods
       chainNode() {}
       chainNode(const T& element)
          {this->element = element;}
       chainNode(const T& element, chainNode<T>* next)
          {this->element = element;
           this->next = next;}
        };

    #endif

You can't delete the original chain from here. It is passed as a reference which implies that it will exist throughout the function body. (Toughr you can empty it, like your did for B and C).

In C++ to be able to destroy an object you must first be sure that this object has been dynamically allocated (ie with new ). Then, you need a pointer to that object, not a reference.

So you need to change your function like this:

template <class T> 
void chain<T>split(chain<T>* A, chain<T>& B, chain<T>& C) 
{
     .... // same as before
     delete A;
} 

NOTE 1: I lied, you could take a pointer from the reference (ie delete &A ) but that would be a very bad practice.

NOTE 2: Several little things you could improve:

  • store end() somewhere ( chain<T>::iterator end = A.end() ) to avoid computing it each time.
  • C.listsize should probably be a function, if it is not a function, don't store its value in a variable.
  • n = n+1 should be ++n;
  • Don't reuse the same loop variable ( for (int j = 0; ... )
  • If your compiler is recent enough use the for each loop ( for (T& t: A) ) and auto
  • You should add an empty method to chain to factor the code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM