0

私は練習用に独自のリストクラスを作成しました。これは次のとおりです。

#pragma once

#include <iostream>

using namespace std;

// A linked node structure.
template <typename T>
struct LinkedNode
{
    T data;
    LinkedNode<T>* next;
    LinkedNode<T>* prev;
};

// Class linked list.
template <typename T>
class LinkedList
{
public:

    // Constructor
    LinkedList()
    {
        mFirst = 0;
        mLast = 0;
    }

    LinkedList(const LinkedList& rhs)
    {
        mFirst = 0;
        mLast = 0;

        // Get a pointer to the first node of rhs.
        LinkedNode<T>* current = rhs.mFirst;

        // While not at the end of the rhs linked list.
        while( current != 0 )
        {
            insertLast( current->data );
            current = current->next;
        }
    }

    // Destructor
    ~LinkedList()
    {
        destroy();
    }

    // Overload
    LinkedList& operator=(const LinkedList& rhs)
    {
        // Check for self assignment
        if ( this == &rhs )
            return *this;

        // Get a pointer to the first node of rhs.
        LinkedNode<T>* current = rhs.mFirst;

        // While not at the end of the rhs linked list.
        while( current != 0 )
        {
            insertLast( current->data );
            current = current->next;
        }

        // Chain assignments a = b = c = d
        return *this;
    }

    // Check if list is empty.
    bool isEmpty()
    {
        if( mFirst == 0 && mLast == 0 )
            return true;
        else
            return false;
    }

    // Return first and last nodes.
    LinkedNode<T>* getFirst() { return mFirst; };
    LinkedNode<T>* getLast()  { return mLast;  };

    void insertFirst(T tData);
    void insertLast(T tData);
    bool insertAfter(T tKey, T tData);
    void removeFirst();
    void removeLast();
    void remove(T removalCandidate);
    void destroy();

private:

    LinkedNode<T>* mFirst;
    LinkedNode<T>* mLast;
};

template <typename T>
bool LinkedList<T>::insertAfter(T tKey, T tData)
{
    if( isEmpty() ) return false;

    // Get a pointer to the front of the list
    LinkedNode<T>* current = mFirst;

    // Loop until we find the tKey (the value of the node to insert after)
    while( current->data != tKey )
    {
        // Hop to the next node.
        current = current->next;

        // Test if we reached the end, if we did we didn't find the node to insert after (tKey)
        if( current == 0 )
            return false;
    }

    // Allocate memory for the new node to insert.
    LinkedNode<T>* newNode = new LinkedNode<T>();
    newNode->data = tData;

    // Special case: Are we inserting after the last node?
    if( current == mLast )
    {
        newNode->next = 0;
        mLast = newNode;
    }
    // No, else link in new node after the current node.
    else
    {
        newNode->next = current->next;
        newNode->next->prev = newNode;
    }

    newNode->prev = current;
    current->next = newNode;

    return true;
}

template <typename T>
void LinkedList<T>::insertFirst(T tData)
{
    LinkedNode<T>* newNode = new LinkedNode<T>();
    newNode->data = tData;

    // If the list is empty, then this is the first and last node and doesn't have a previous pointer.
    if( isEmpty() )
        mLast = newNode;
    // If the list is not empty, the new node becomes the previous node of the current first node.
    else
        mFirst->prev = newNode;

    // The new node's next pointer is the old first pointer. May be null if this is the first node being added to the list.
    newNode->next = mFirst;

    //The new node becomes the first node.
    mFirst = newNode;   
}

template <typename T>
void LinkedList<T>::insertLast(T tData)
{
    LinkedNode<T>* newNode = new LinkedNode<T>();
    newNode->data = tData;

    if( isEmpty() )
        mFirst = newNode;
    else
        mLast->next = newNode;

    newNode->prev = mLast;

    mLast = newNode;
}

template <typename T>
void LinkedList<T>::removeFirst()
{

    if( !isEmpty() )
    {
        LinkedNode<T>* current = mFirst;

        if( mFirst == mLast )
        {
            mFirst->next = 0;
            mLast->prev = 0;
        }
        else
        {
            mFirst = current->next;
            mFirst->prev = 0;
        }

        delete current;
        current = 0;
    }   
}

template <typename T>
void LinkedList<T>::removeLast()
{
    if( !isEmpty() )
    {
        LinkedNode<T>* current = mLast;

        if( mFirst == mLast )
        {
            mFirst = 0;
            mLast = 0;
        }
        else
        {
            mLast = current->prev;
            mLast->next = 0;
        }

        delete current;
        current = 0;
    }
}

template <typename T>
void LinkedList<T>::remove(T removalCandidate)
{
    LinkedNode<T>* current = mFirst;

    if( isEmpty() )
    {
        cout << "List is empty!" << endl;
    }
    else
    {
        while( current->data != removalCandidate )
        {
            if( current->data == removalCandidate )
            {
                break;
            }
            current = current->next;
        }
    }

    if( current == mFirst )
        removeFirst();
    else if ( current == mLast )
        removeLast();
    else
    {
        // Create two linked nodes to access the next and prev nodes.
        LinkedNode<T>* left  = current->prev;
        LinkedNode<T>* right = current->next;

        left->next = right;
        right->prev = left;
    }

    delete current;
    current = 0;
}

template <typename T>
void LinkedList<T>::destroy()
{
    // Is there at least one node in the list?
    if( mFirst != 0 )
    {
        // Get a pointer to the first node.
        LinkedNode<T>* current = mFirst;

        // Loop until we reach the end of list.
        while( current != 0 )
        {
            // Save the current node.
            LinkedNode<T>* oldNode = current;

            // Move to next node.
            current = current->next;

            // Delete saved node.
            delete oldNode;
            oldNode = 0;
        }
    }

    mFirst = 0;
}

次に、スタックとキューのクラスも作成し、両方をテストして、文字列が回文であるかどうかを確認します。それはすべてうまくいきます。ただし、リストクラスでdestroyメソッドを実行すると、次のエラーがスローされます。ブロックタイプは有効(pHead-> nBlockUse)エラーです。

delete oldNode;

ライン。

キューコード:

#pragma once

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

#include <cassert>

template <typename T>
class Queue
{
public:
    Queue(){};

    ~Queue()
    {
        mList.destroy();
    }

    T& getFirst()
    {
        assert( !isEmpty() );
        return mList.getFirst()->data;
    }

    bool isEmpty( void )
    {
        return mList.isEmpty();
    }

    void push( T newElement )
    {
        mList.insertLast( newElement );
    }

    void pop()
    {
        mList.removeFirst();
    }

private:
    LinkedList<T> mList;
};

スタックコード:

#pragma once

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

#include <cassert>

template <typename T>
class Stack
{
public:
    Stack(){};

    ~Stack()
    {
        mList.destroy();    
    }

    T& getTopItem()
    {
        // Throw error if list is empty.
        assert( !isEmpty() );

        return mList.getLast()->data;
    }

    bool isEmpty( void )
    {
        return mList.isEmpty(); 
    }

    void push( T newElement )
    {
        mList.insertLast( newElement );
    }

    void pop()
    {
        mList.removeLast();
    }

private:
    LinkedList<T> mList;
};

メインコード:

#include "Stack.h"
#include "Queue.h"
#include <iostream>
#include <string>
using namespace std;

int main()
{

    Stack<char> strStack;
    Queue<char> strQueue;

    cout << "Enter a string: ";
    string input = "";
    getline(cin, input);

    for( unsigned int i = 0; i < input.length(); ++i )
    {
        strStack.push( input[i] );
        strQueue.push( input[i] );
    }

    bool isPalindrome = true;

    // FIX PALINDROME AND ASSERTION FAIL

    for( unsigned int j = 0; j < input.length(); ++j )
    {
        if( strStack.getTopItem() != strQueue.getFirst() )
        {
            isPalindrome = false;
            break; // Exit for loop early.
        }

        // Get rid of next element out.
        strStack.pop();
        strQueue.pop();
    }

    cout << input << " is palindrome: " << isPalindrome << endl;
}

理由はわかりませんが、助けていただければ幸いです。

4

2 に答える 2

3

問題はremoveFirst関数にあります。リストの最後のノードを削除するとき(つまりmFirst == mLasttrue)、ノードリンクポインタをに設定してから0、ノードを削除します。これで、とは削除されたノードmFirstmLast指します。

nextprevリンクをに設定する代わりに、とをに設定0する必要がmFirstあります。ですでに行っているように。mLast0removeLast

于 2012-11-13T09:43:37.840 に答える
2

destroy()メソッドが戻る直前にmFirstをNULL(0)に設定していないためです。destroy()を複数回呼び出すと、ポインターを2回削除しようとした結果として、この種のcrtアサーションが発生します。キュークラスはそのデストラクタでmList.destroyを呼び出しますが、mListのデストラクタは再びdestroyを呼び出します。

于 2012-11-13T09:23:51.677 に答える