如何使堆栈动态增长
How to make a stack grow dynamically?
这是我的Stack类的小程序:
#include <iostream>
using namespace std;
#include <iomanip>
template <typename T>
class Stack
{
private:
T *stackPtr;
int size;
T top;
public:
Stack(int = 10);
~Stack();
bool push(const T );
bool pop();
void printStack();
};
int main()
{
Stack <int> myStack(5);
cout << "Push 5 elements to stack: ";
int ct = 0;
while (ct++ != 5)
{
int temp;
cin >> temp;
myStack.push(temp);
}
myStack.printStack();
cout << "nErasing two elements:n";
myStack.pop();
myStack.pop();
myStack.printStack();
return 0;
}
template <typename T>
Stack<T>::Stack(int s)
{
size = s > 0 ? s: 10;
stackPtr = new T[size];
top = -1;
}
template <typename T>
Stack<T>::~Stack()
{
delete [] stackPtr;
}
template <typename T>
bool Stack<T>::push(const T value)
{
if (top == size - 1)
return false;
top++;
stackPtr[top] = value;
return true;
}
template <typename T>
bool Stack<T>::pop()
{
if (top == - 1)
return false;
stackPtr[top] = 0;
top--;
return true;
}
template <typename T>
void Stack<T>::printStack()
{
for (int ix = size -1; ix >= 0; ix--)
cout << "|" << setw(4) << stackPtr[ix] << endl;
}
因此,为了使用这样的堆栈,如果我需要 10 个元素,我应该在使用前在构造函数中声明它的大小,就像 Stack<int> newstack(10)
一样。那么,如果我不知道堆栈的最终大小该怎么办?如何通过推动元素来使其动态增长?我一直在寻找解决方案,但我所有的想法仍然都是计算元素,然后声明一个堆栈以适应元素编号。
首先,你知道C++内置std::stack
,不是吗?对于其余的答案,我假设你有理由不使用它(也许这是一个学习练习)。
实现你想要的一个非常天真的方法是:
- 每次添加元素时,分配一个大小为 + 1 的新数组,并带有
new[]
. - 将旧数组和新元素的所有元素复制到新数组中。
-
delete[]
旧阵列。 stackPtr
指向新阵列。
撇开此解决方案的所有性能和异常安全陷阱不谈,如果您的元素类型T
没有默认构造函数,它怎么可能工作?它甚至不会编译。实际上,您的类会失败,因为它是以下T
:
struct CannotUseInThisStack
{
CannotUseInThisStack(int) {} // no default constructor
};
Stack<CannotUseInThisStack> s; // error
真正的解决方案是:不要使用new[]
和delete[]
。根据std::vector
(或std::deque
来实现您的堆栈,这正是std::stack
默认所做的! std::vector
支持开箱即用的动态增长,以更好的方式,无需在每次添加元素时连续重新分配,也不需要能够默认构造T
。
这理所当然地导致了一个问题,即std::vector
如何才能做到这一切。
答案是std::vector
,或者更确切地说,它的标准分配器std::allocator
,不是在new[]
和delete[]
方面实现的,而是在放置新方面实现的。内存分配和元素构造是分开的。请参阅std::allocator:allocate
。这解决了缺少默认构造函数的问题。首先分配原始内存,然后使用复制构造函数在该原始内存位置构造新元素(在 C++11 中,您也有完美的转发来就地构造T
,但这有点偏离主题)。
使用放置新也允许std::vector
的容量呈指数级增长。容器不需要在每次添加元素时重新分配内存;它预先为更多元素分配原始记忆(类似于克里斯托夫在他的答案中所做的)。仅当超过当前容量时,才会进行重新分配。
有了new[]
和delete[]
,这样复杂的机制是不可能的。
通常,如果您想了解严肃的容器设计,请查看编译器如何实现所有C++标准容器。
您始终可以使用链接列表进行此操作。如果你想插入到堆栈中,那么你只需在链表的头部放置一个节点。要弹出,您只需将其删除即可。现在你可能会想如何实现这种语句,比如 堆栈S=new Stack(5);
.
您只需保留一个计数器来保持此值。您可以对此变量进行任何检查(如堆栈溢出等)。您只需让它像 STL 支持C++一样动态,并且很容易使用它。
我想建议使用std::stack()
不会是您所期望的答案;-)
在达到限制时分配更多空间:
template <typename T>
bool Stack<T>::push(const T value)
{
if (top == size - 1) {
//return false;
size_t s = size + 10; // for example increase by 10
T *ps = new (nothrow) T[s]; // allocate new region
if (ps==nullptr)
return false; // out of memory
for (size_t i=0; i<size; i++)
ps[i] = stackPtr[i];
delete[] stackPtr;
stackPtr = ps;
size = s; // stack is now bigger,
} // so continue as if there was no problem
top++;
stackPtr[top] = value;
return true;
}
问题是,增加多少堆栈。 你可以像这里一样使用常量方法,但最好考虑一个成员变量并在构造函数中初始化它。
编辑:我使用了带有nothrow
的新内容,以避免在内存不足的情况下引发异常,因为您的签名预见了操作成功的返回代码。
- 如何在C++中为堆栈动态创建结构?
- c++ 动态内存 堆栈中的分配
- 在堆或堆栈上分配的动态创建的字符串 - C
- 使用数组C++的动态堆栈
- 我正在尝试使用回溯来解决 N queen 问题,但在编译时它会给出运行时错误(动态堆栈缓冲区溢出)
- 为什么不能在 Visual C++ 中动态分配堆栈内存?但海湾合作委员会可以做到
- 为什么要对堆栈中的内存使用自定义动态内存分配?
- 我如何转换一个基于动态的,基于指针的int堆栈,以便将其打印成字符串
- 当一个类在构造函数处动态分配自己时,为什么会发生堆栈溢出而不是 std::bad_alloc
- 堆栈动态和堆栈动态数组
- 附加到具有非动态分配堆栈的向量
- 可以作为固定大小(堆栈)和动态大小(堆)工作的数组封装程序
- 链表与动态数组用于使用向量类实现堆栈
- 除了堆栈和堆模型之外,还为C++实现了哪些其他形式的自动和动态存储
- 带有指针的动态堆栈结构
- 动态堆栈、编译时出错、dev编译器和g++
- C++ 中的动态堆栈数据类型声明
- 如何显示动态堆栈和队列(c++)中的所有元素
- C++Visual Studio 2010,在实现动态堆栈时编译错误C3867
- 动态堆栈分配(来自c++思维)