目录
一.构造栈
使用构造函数
代码:
二.销毁栈
使用析构函数
代码
三.判空,判满
四.扩容
代码
五.入栈,出栈
代码
六.取栈顶元素
代码
代码合集
template< class T>模板
T为当前栈的数据类型
栈类型有三个属性:栈的空间大小,栈顶指针,以及用以存储元素的空间。
一.构造栈
使用构造函数
初始化栈类型的三个属性:设无任何元素的栈的栈顶指针为-1。
使用new关键字为栈申请空间大小。
new的作用:计算类型大小,malloc开辟空间,构造对象,将空间的地址返回
为了判断申请空间是否成功,需要判空。根据new的特性,我们不能直接使用nullptr去判空,因为new关键字出现异常会直接停止,系统跳出异常
代码:
Seqstack(int sz = STACK_INIT_SIZE) :_top(-1), _size{ sz }, _data{ nullptr }{
_data = new(nothrow) T [sz];
if (nullptr == _data) {
exit(EXIT_FAILURE);
}
}
二.销毁栈
使用析构函数
因为用new关键字开辟空间,所以我们要用delete关键字收回空间并free
由于_data是一个数组,需要用delete[]去析构。
这里的构造函数和析构函数,小白认为和人的诞生死亡是相同的,可以这么简单认为。
当栈空间由系统收回后,_size空间大小变为0,栈顶指针指向最底。
代码
~Seqstack() {
delete[]_data;
_data = nullptr;
_size = 0;
_top = -1;
}
三.判空,判满
这里有任何疑问可以参考小白在数据结构处所写的栈。
int GetSize() {
return _top + 1;
}
int GetCapth() {
return _size;
}
bool Empty() {
return _top+1==0;
}
bool Full() {
return _top+1==_size;
}
四.扩容
这里注意两点:
1.开辟新数组后,新数组的长度是原来数组的2倍,而当你使用new关键字的时候,new关键字是没有将原先数组的值拷贝过去的功能,所以得使用内存函数,将内容一字节一字节拷贝过去。而原数组和新数组长度不一样,一定要注意这个,否则拷贝过去后,新数组的部分值是随机值。
如果用realloc函数就没有这么麻烦。
2.当把原先的数组拷贝完后,我们要把新开辟的数组返回给原数组,需要干的第一步就是把原先数组资源释放掉,然后把原数组里的元素删干净,并指向空,防止出现空悬指针。最后将新构建的赋值过去即可。
代码
new
bool Inc( ) {
int newsize = STACK_INIT_SIZE * STACK_INC_SIZE;
if (newsize <= _size)return true;
//在这里注意 申请空间以2倍扩容
T* newdata = new(nothrow)T [newsize];
if (newdata == nullptr) {
return false;
}
memmove(newdata, _data, sizeof(T) * GetSize());
delete[]_data;
_data = nullptr;
_data = newdata;
_size = STACK_INIT_SIZE * 2;
return true;
}
realloc
bool Inc(size_t newsz)
{
if (newsz <= GetCapt())
{
return true;
}
T* newdata = (T*)realloc(_data, sizeof(T) * newsz);
if (nullptr == newdata)return false;
_data = newdata;
_size = newsz;
return true;
}
五.入栈,出栈
这里没有什么难点。有问题的宝子可以去看看小白在数据结构处写的栈
代码
void Push(T val) {
if (Full() && !Inc()) {
return;
}
_data[++_top] = val;
}
void Pop() {
if (Empty()) {
return;
}
_top--;
}
六.取栈顶元素
这里我们使用引用将值返回,因为当函数结束后,函数所占的栈空间释放后,我们所建的栈还在,栈顶元素值仍在,所以可以使用引用去返回。
注意:引用返回:当返回的值受到函数调用结束影响,即存在僵亡值时,不能使用引用返回。不安全
同理我们也可以使用钓鱼的方式将取栈顶元素和出栈合二为一
代码
T& Top()const {
return _data[_top];
}
T& GetPop() {
assert(_data != nullptr);
return _data[_top--];
}
代码合集
#include<iostream>
#include<cstring>
#include<assert.h>
using namespace std;
template<class T>
class Seqstack {
private:
enum { STACK_INIT_SIZE = 10, STACK_INC_SIZE = 2 };
T* _data;
int _size;
int _top;
public:
Seqstack(int sz = STACK_INIT_SIZE) :_top(-1), _size{ sz }, _data{ nullptr }{
_data = new(nothrow) T [sz];
if (nullptr == _data) {
exit(EXIT_FAILURE);
}
}
~Seqstack() {
delete[]_data;
_data = nullptr;
_size = 0;
_top = -1;
}
int GetSize() {
return _top + 1;
}
int GetCapth() {
return _size;
}
bool Empty() {
return _top+1==0;
}
bool Full() {
return _top+1==_size;
}
bool Inc( ) {
int newsize = STACK_INIT_SIZE * STACK_INC_SIZE;
if (newsize <= _size)return true;
//在这里注意 申请空间以2倍扩容
T* newdata = new(nothrow)T [newsize];
if (newdata == nullptr) {
return false;
}
memmove(newdata, _data, sizeof(T) * GetSize());
delete[]_data;
_data = nullptr;
_data = newdata;
_size = STACK_INIT_SIZE * 2;
return true;
}
void Push(T val) {
if (Full() && !Inc()) {
return;
}
_data[++_top] = val;
}
T& Top()const {
return _data[_top];
}
void Pop() {
if (Empty()) {
return;
}
_top--;
}
T& GetPop() {
assert(_data != nullptr);
return _data[_top--];
}
};
int main() {
Seqstack<int> mys;
for (int i = 1; i < 20; i++) {
mys.Push(i);
}
int val_0 = 0;
cout << mys.Top() << endl;
while (!mys.Empty()) {
val_0 = mys.GetPop();
cout << val_0 << " ";
}
cout << endl;
Seqstack<double> mys1;
mys1.Push(12.23);
mys1.Push(23.34);
mys1.Push(34.45);
mys1.Push(45.56);
mys1.Push(67.78);
mys1.Push(78.89);
mys1.Push(89.90);
mys1.Push(100.10);
double val = 0.0;
cout << mys1.Top() << endl;
while (!mys1.Empty()) {
val = mys1.GetPop();
cout << val << " ";
}
}
结果:
小白在数据结构中所写的顺序栈:Day 08顺序栈_早点打完工去睡觉的博客-CSDN博客
good good study,day day up!