Реализация стека C ++ (домашнее задание) PT.II - PullRequest
2 голосов
/ 11 октября 2011

ОК, прогресс здесь.Мой вопрос сейчас связан с копированием и глубоким копированием.Мой стек в настоящее время постоянно падает, и у меня есть ощущение, что это происходит из-за того, что класс, от которого он зависит, не позволяет создавать копии и перегружать операторы.Но в любом случае вот мой код (я прошу прощения за количество кода, но, вероятно, необходимо понять, где я терплю неудачу):

Зависимый класс, связанный список

#ifndef linkList_H
#define linkList_H


//
// Create an object to represent a Node in the linked list object
// (For now, the objects to be put in the list will be integers)
//
struct Node
{
    int   number;
    Node* next;
    Node* prev;

    // needs copy constructor?
    // needs overloaded assignment operators for copying?
    // needs overloaded operators for incrementing and decrementing?
};


//
// Create an object to keep track of all parts in the list
//
class List
{
public:

    //
    // Contstructor intializes all member data
    //
    List() : m_size(0), m_listHead(0) {}

    //
    // methods to return size of list and list head
    //
    Node*    getListHead() const { return m_listHead; }
    unsigned getListSize() const { return m_size; }

    //
    // methods for adding and inserting a new node to the linked list, 
    // retrieving and deleting a specified node in the list
    //
    void  addNode(int num);
    void  deleteNode(Node* current);
    void  insertHead(Node* current);
    void  insertAfter(Node* current, int newValue);
    void  insertBefore(Node* current, int newValue);

    Node* retrieveNode(unsigned position);

private:

    //
    // member data consists of an unsigned integer representing
    // the list size and a pointer to a Node object representing head
    //
    Node*    m_listHead;
    unsigned m_size;
};

#endif

РеализацияconnectedList

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

using namespace std;


//
// Adds a new node to the linked list
//
void List::addNode(int num)
{
    Node *newNode = new Node;
    newNode->number = num;
    newNode->next = m_listHead;

    if( m_listHead )
        m_listHead->prev = newNode;

    m_listHead = newNode;
    ++m_size;
}


//
// Inserts a node which has already been set to front
// of the list
//
void List::insertHead(Node* current)
{
    int value = current->number;
    deleteNode(current);
    addNode(value);
}


//
// Inserts a node which has already been set before a
// specified location in the list
//
void List::insertBefore(Node* current, int newValue)
{
    current = current->prev;
    current->number = newValue;
}


//
// Inserts a node which has already been set before a
// specified location in the list
//
void List::insertAfter(Node* current, int newValue)
{
    current = current->next;
    current->number = newValue;
}


//
// Deletes a node from a specified position in linked list
//
void List::deleteNode(Node* current)
{
    --m_size;

    if(current == m_listHead) 
        m_listHead = current->next;
    if(current->prev) 
        current->prev->next = current->next;
    if(current->next) 
       current->next->prev = current->prev;
}


//
// Retrieves a specified node from the list
//
Node* List::retrieveNode(unsigned position)
{
    if(position > (m_size-1) || position < 0)
    {
        cout << "Can't access node; out of list bounds";
        cout << endl;
        cout << endl;

        exit(EXIT_FAILURE);
    }

    Node* current = m_listHead;
    unsigned pos = 0;

    while(current != 0 && pos != position)
    {
        current = current->next;
        ++pos;
    }

    return current;
}

Вот класс стека:

#ifndef stack_H
#define stack_H

#include "linkList.h"


class Stack
{
public:

    //
    // Constructor, copy constructor and destructor to initialize stack 
    // data, copy data and clear up memory, respectively
    //
   Stack() : m_top(0), m_stack(new List()) {}
   Stack(const Stack &rhs);

   ~Stack() { delete [] m_stack; }

    //
    // functionality to determine if stack is empty
    //
    bool isEmpty();

    //
    // methods for pushing data on to stack and for
    // popping data from the stack
    //
    void push(int newValue);
    int  pop();

    //
    // accessor functions for retrieving the value on top of stack
    // and for returning the stack size
    //
    int getTop() const { return m_top->number; }
    int getSize() const { return m_stack->getListSize(); }

    //
    // overloaded assignment operator for copying stack
    //
    Stack& operator=(const Stack &rhs);

private:

    //
    // member data which represent the stack, the top
    // of the stack and the size of the stack
    //
    Node* m_top;
    List* m_stack;
};

#endif

И, наконец, вот реализация стека

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

using namespace std;

//
// Copy constructor
//
Stack::Stack(const Stack &rhs)
    : m_top(rhs.m_top), m_stack(rhs.m_stack)
{
}

//
// if the Top of stack is zero, return true
//
bool Stack::isEmpty()
{
    if( m_top == 0 ) return true;
    else return false;
}

//
// increment stack pointer, place new value in stack
//
void Stack::push(int newValue)
{
    ++m_top;               
    m_top->number = newValue;   // crashes on this statement
}

//
// if the stack is empty, throw an error message
//
int Stack::pop()
{
    if( isEmpty() )
    {
        cout << "Error: stack underflow" << endl;
        exit(EXIT_FAILURE);
    }

    --m_top;
    return (m_top + 1)->number;

}


Stack& Stack::operator=(const Stack &rhs)
{
    if( this != &rhs )
        delete [] m_stack;

    m_stack = new List();
    m_stack = rhs.m_stack;
    m_top = rhs.m_top;

   return *this;
}

Программа аварийно завершает работу после этого простого кода вОсновная программа:

Stack stack;

stack.push(1);

Опять же, извините за количество кода здесь.Я полагаю, что моя проблема здесь в том, что объекту Node нужны перегруженные операторы для того, чтобы «увеличивать» или «уменьшать», чтобы создать / удалить узел, когда значение помещается в стек.Это тот случай?Кроме того, я не уверен, нужен ли мне конструктор копирования или нет для объекта Node.Здесь может быть еще много проблем (может быть, алгоритмы неверны? Возможно, структура копирования некорректна для стека?).Есть идеи?

Ответы [ 5 ]

3 голосов
/ 11 октября 2011

Давайте постранично рассмотрим ваш сценарий сбоя.(хорошо, потому что он имеет только 2 строки!)
Сначала оператор: Stack stack;
Это вызовет конструктор стека, который установит m_top в какое значение?

Далее есть строка: stack.push(1);
В двух операторах stack.push оба будут использовать m_top.
Первым оператором будет ++m_top;
.с какого значения m_top началось, какое значение оно будет иметь сейчас?

Второе утверждение - m_top->number = newValue;
Если вы правильно ответили на предыдущие вопросы о m_top, оноДолжно быть понятно, почему программа падает в этот момент.Также должно быть относительно понятно, как это исправить.

1 голос
/ 12 октября 2011

Прежде всего, вы не можете использовать оператор удаления массива в m_stack (delete [] m_stack), потому что там только один объект, а не массив (m_stack = new List).Это приведет к сбою.(На самом деле я не понимаю, почему он создается динамически.)

Затем вам нужно написать правильный оператор присваивания и конструктор копирования для вашего класса List, который будет копировать узлы,а также деструктор, который очищает выделенные узлы, но это не имеет ничего общего с вашей аварией (но легко вызовет вас в будущем).

Текущая причина аварии, как и другие, сказала:этот стек пытается получить доступ к m_top, пока он нулевой.

Но главная проблема - плохой дизайн, из-за которого вы непонятно используете класс List: /

  • Во-первых, если у вас естьдвухсторонний связанный список, класс List должен также отслеживать указатель хвоста, а не только указатель головы.Это избавит вас от многих головных болей.
  • Тогда addHead, addTail, insertBefore, insertAfter не должен полагаться на пользователя при создании узлов, но создает их внутри функций и возвращает вновьсозданный узел.
  • Также очень опасно, что указатели next и prev выставлены и могут быть изменены вне класса List.Я предлагаю сделать make prev и next private и предоставить для них геттер, чтобы их нельзя было изменить (в этом случае класс List должен быть другом структуры / класса Node).

Я думаю, это даст вам хорошее начало, как переписать List и Stack с нуля.Кроме того, следите за владением узлами, которые сейчас не обрабатываются.

1 голос
/ 11 октября 2011

m_top установлен в 0 в вашем конструкторе. Но ...

Ваш Stack просто должен украсить ваш List очень специфическим способом. Если коротко взглянуть на заголовок List, все это будет относительно легко реализовать, если вы понимаете, как работает стек ...

Ваш Stack не должен держать «верх». Это должно быть реализовано с точки зрения вашего List. Нажатие на стек должно добавить новый узел в начало списка, а извлечение из стека должно удалить узел в начале списка.

0 голосов
/ 11 октября 2011

Лучший подход - тестировать эти классы по одному. Поскольку стек зависит от списка, сначала отладьте список. Я предполагаю, что у вас есть доступ к отладчику. Если нет, то узнайте, как его использовать. Вам также нужно написать тестовый код для класса List.

Удачи.

0 голосов
/ 11 октября 2011

Вы инициализируете m_top в 0 (ноль) в конструкторе, затем пытаетесь использовать его в push()

...