在上一篇我们学习了顺序栈的实现,但是大家要思考一个问题,就是顺序栈在初始化的时候会申请一大片连续的内存空间,这样在输入较少的情况下会造成大量的内存空间的浪费。那么要怎么解决这个问题呢?
1、在沿着顺序栈的思路上我们可以取用共享栈的方法,让两个栈共享一片内存空间,这个时候我们在初始化的时候只需要定义两个栈顶指针top和bottom,分别让其指向设定容量的底部和顶部,比如我们设定MaxSize=100,那么我们就可以让Top初始化为-1,bottom初始化为100,在进行相关的操作即可。注意此时栈满的条件为 top+1 == bottom
2、使用和链表相同的思路,利用链式存储的方法来定义栈的结构,这样我们只需要考虑第一个元素的操作即可,而且由于链式存储的特点,可以很方便的去添加和修改结点,同时由于可以使用零散的内存空间,内存的利用率也得到了很大的提高,不再需要一大片的连续内存。
#include <iostream>
using namespace std;
#define ElemType int
typedef struct LinkStack {
ElemType data;
struct LinkStack *next;
} stackNode, *LiStack;
//此处使用了头结点的方法去初始化,大家也可以尝试不使用头结点的方法,道理都是一样的
void InitStack(LiStack &L) {
L = (LiStack) malloc(sizeof(stackNode));
L->next = nullptr;
}
bool isEmpty(LiStack liStack) {
return liStack->next == nullptr;
}
bool Push(LiStack &L, int e) {
stackNode *node = (stackNode *) malloc(sizeof(stackNode));
node->data = e;
node->next = L->next;
L->next = node;
return true;
}
bool Pop(LiStack &L, int &e) {
if (isEmpty(L))
return false;
stackNode *pop = L->next;
e = pop->data;
if (pop->next != nullptr) {
L->next = pop->next;
} else {
L->next = nullptr;
}
//注意要手动释放内存空间
free(pop);
return true;
}
bool Peek(LiStack L, int &e) {
if (isEmpty(L))
return false;
e = L->next->data;
return true;
}
void PrintStack(LiStack L) {
L = L->next;
while (L) {
printf("%d ", L->data);
L = L->next;
}
printf("\n");
}
int main() {
LiStack s;
InitStack(s);
int val;
scanf("%d", &val);
while (val != -1) {
Push(s, val);
scanf("%d", &val);
}
cout << "栈中的值为:" << endl;
PrintStack(s);
/*此处重复使用e,会导致即使栈空,仍然会打印出pop的值,函数本身没有问题,换个字母就行,
*或者说是将函数的返回参数改成结点类型或ElemTpye即可,较为简单,这里就不重复造轮子了
*/
int e;
Pop(s, e);
cout << "the pop value is " << e << endl;
Pop(s, e);
cout << "the pop value is " << e << endl;
Pop(s, e);
cout << "the pop value is " << e << endl;
Peek(s, e);
cout << "the peek value is " << e << endl;
PrintStack(s);
return 0;
}