进展顺利。我现在的问题是关于拷贝构造和深度拷贝。我的堆栈目前一直在崩溃,我有一种感觉,它正在这样做,因为它所依赖的类不允许复制构造和操作符重载。但无论如何,这是我的代码(我为代码量道歉,但它可能是必要的,以了解我失败的地方):
依赖类,链表
#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
linkedList的实现
#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对象的复制构造函数。这里可能有更多的问题(也许算法是不正确的?也许复制构造是不正确的堆栈?)。什么好主意吗?
让我们逐行分析崩溃场景。(很好,因为它只有两行!)
首先是语句:Stack stack;
这将调用堆栈构造函数,它将把m_top
设置为什么值?
下一行是:stack.push(1);
stack.push
的两个语句都将使用m_top
。
第一个语句是++m_top;
给定m_top
开始的值,它现在的值是多少?
第二个语句是m_top->number = newValue;
如果您正确地回答了前面关于m_top
的问题,那么此时程序崩溃的原因就应该很清楚了。如何修复它也应该相对清楚。
m_top
在构造函数中设置为0
。但是…
你的Stack
只需要以一种非常具体的方式装饰你的List
。从简短地看你的List
头,这一切都应该是相对容易实现的,如果你了解堆栈是如何工作的…
你的Stack
不需要保持"顶部"。它应该根据您的List
来实现。push到堆栈应该在列表的前面添加一个新节点,而弹出堆栈应该从列表的前面删除一个节点。
首先,你不能在m_stack (delete [] m_stack
)上使用数组删除操作符,因为那里只有一个对象而不是数组(m_stack = new List
)。这将导致崩溃。(实际上我不明白为什么它是动态创建的。)
当前的崩溃原因,就像其他人说的,Stack试图访问m_top,而它是空的。
但是主要的问题是糟糕的设计,它使你以一种不明确的方式使用List类:/- 首先,如果你有一个双向链表,list类也应该跟踪尾部指针而不仅仅是头部指针。这会让你从很多头痛中解脱出来。
- 那么,
addHead, addTail, insertBefore, insertAfter
不应该依赖于用户创建节点,而是在函数中创建节点,并返回新创建的节点。 此外,
next
和prev
指针暴露在外,并且可以在List类之外更改,这是非常不安全的。我建议你将prev和next设置为私有,并为它们公开一个getter,这样它们就不能被更改(在这种情况下,List类需要是Node结构/类的朋友)。我认为,这些将给你一个很好的开始,如何从头开始重写列表和堆栈。另外,请注意当前未处理的节点的所有权。
在构造函数中将m_top
初始化为0
(null),然后尝试在push()
中使用它
最好的方法是一次测试这些类中的一个。因为Stack依赖于List,所以先调试List。我假设您可以访问调试器。如果没有,就去买一个,学着怎么用。您还需要为List类编写一些测试代码。
好运。