#include <iostream>
using namespace std;
template<class Datatype>
class Node
{
public:
Node()
{
next = NULL;
prev = NULL;
}
Node* getNext()
{
return next;
}
Node* getPrev()
{
return prev;
}
Datatype* getData()
{
return &data;
}
void changeNext()
{
next = NULL;
}
void changeNext(Node& nextNode)
{
next = &nextNode;
}
void changePrev()
{
prev = NULL;
}
void changePrev(Node& prevNode)
{
prev = &prevNode;
}
Node* addNext(Node &);
Node* addPrev(Node &);
void nodeDel();
void addData(Datatype &);
private:
Node* next;
Node* prev;
Datatype data;
};
template<class Datatype>
class Stack
{
public:
Stack() : head( NULL )
{
}
int push(Datatype &);
int pop(Datatype &);
Datatype* peek();
private:
Node<Datatype> *head;
};
template <class Datatype>
Node<Datatype>* Node<Datatype>::addNext(Node<Datatype>& exi_node)
{
if (exi_node.getNext() == NULL)
{
changePrev(exi_node);
exi_node.changeNext(*this);
}
else
{
Node* next = exi_node.getNext();
changePrev(exi_node);
changeNext(*next);
exi_node.changeNext(*this);
next -> changePrev(*this);
}
return &exi_node;
}
template <class Datatype>
Node<Datatype>* Node<Datatype>::addPrev(Node<Datatype>& exi_node)
{
if (exi_node.getPrev() == NULL)
{
changeNext(exi_node);
exi_node.changePrev(*this);
}
else
{
Node* prev = exi_node.getPrev();
changePrev(*prev);
changeNext(exi_node);
exi_node.changePrev(*this);
prev -> changeNext(*this);
}
return &exi_node;
}
template<class Datatype>
void Node<Datatype>::nodeDel()
{
if (prev == NULL && next == NULL)
;
else if (prev == NULL)
{
Node* next = getNext();
next -> changePrev();
}
else if (next == NULL)
{
Node* prev = getPrev();
prev -> changeNext();
}
else
{
Node* next = getNext();
Node* prev = getPrev();
next -> changePrev(*prev);
prev -> changeNext(*next);
}
delete this;
return;
}
template <class Datatype>
void Node<Datatype>::addData(Datatype &new_data)
{
data = new_data;
}
template <class Datatype>
int Stack<Datatype>::push(Datatype &new_data)
{
Node<Datatype> *pt_node = new Node<Datatype>;
if (pt_node == NULL)
return -1;
pt_node -> addData(new_data);
if (head == NULL)
head = pt_node;
else
{
pt_node -> addPrev(*head);
head = pt_node;
}
cout << *(head -> getData()) << endl;
return 0;
}
template <class Datatype>
int Stack<Datatype>::pop(Datatype &pop_data)
{
if (head == NULL)
return 0;
pop_data = *(head -> getData());
if (head -> getNext() == NULL)
{
delete head;
head = NULL;
}
else
{
Node<Datatype>* temp = head;
head = head -> getNext();
delete temp;
}
return 1;
}
template <class Datatype>
Datatype* Stack<Datatype>::peek()
{
return (this->head)->getData();
}
这是一个非常简单的堆栈。 Stack类为用户提供了一些接口,并且指针指向第一个Node。 Node类有两个指向两个方向的指针,也有一个数据字段。 现在,我想在我的Stack中添加一个函数,即在O(1)中找到堆栈中的最小值。一种方法是在Node类中添加一个字段“local_min”,它记录自身下面的最小值。这样,pop(),push(),find_min()都可以在O(1)中完成。 我的直觉是继承Node和Stack,因为我只需要添加一个新函数。但是,我觉得这很不方便。我必须重写几乎所有的功能。 Node和Stack中的指针指向Node类。如果我使用New_Node之类的新类,则必须更改所有内容。 有什么好方法让我做这个扩展吗?我真的觉得继承应该在这里运作良好。但是,我无法理解。
答案 0 :(得分:2)
您的Stack
的编写方式不是为了便于重复使用OO:您还没有虚拟析构函数,派生类型可能希望覆盖的成员函数也不是虚拟的(具体而言) push
和pop
)。因此,编写一个使用Composition的新类更加清晰 - 将Stack
对象存储为数据成员。然后无需更改Node
- 您只需向Stack<Node*>
课程添加StackWithMin
,并仅在数据{{1}时推送/弹出额外的Node*
}推/弹一个改变分钟的Stack
。例如,在推送3,7,5,2,3之后,您的Node
数据成员将是:
StackWithMin
这编码当前min为Stack<Data> Stack<Node*>
[0] 3 &[0]
[1] 7 &[3]
[2] 5
[3] 2
[4] 3
,如果pop删除该元素,那么它也应该从&[3]
中弹出。
另外,Stack<Node*>
是Node
的支持类型,并且该定义不需要作为面向客户端的接口的一部分提供。要隐藏它,请考虑将其放在名为Stack
,Stack_Private
或Stack_Support
的名称空间中,以便客户知道不使用,然后您可以合理地将其设为Stack_Implementation
直接获取/设置数据成员而不是使用访问器功能 - 这将使您的代码更简洁。
答案 1 :(得分:0)
有时在这些情况下,您应该使用非模板基类。该基类可以实现所有不依赖于给定数据类型的函数。
class Node
{
public:
Node() : _next(nullptr), _prev(nullptr) {
}
public:
Node* getNext() {
return _next;
}
Node* getPrev() {
return _prev;
}
void setNext(Node *node) {
_next = node;
}
void setPrev(Node *node) {
_prev = node;
}
private:
Node* _next;
Node* _prev;
};
template <typename Value>
class NodeWithType : public Node
{
public:
NodeWithType() : Node() {
}
public:
const Value& getValue() const {
return _value;
}
void setValue(const Value &value) {
_value = value;
}
public:
Value _value;
};
现在,堆栈类可以使用值独立接口。这简化了一切。