1.顺序栈未简化的版本
(1)顺序栈的表示
typedef struct {
int* base;//栈底指针
int* top;//栈顶指针
int stacksize;//栈容量
}SqStack;
(2)顺序栈的初始化
int InitStack(SqStack& s) {
s.base = new int[MaxSize];//给栈分配空间
if (!s.base) exit(OVERFLOW);
s.top = s.base;
s.stacksize = MaxSize;//修改栈容量
return 1;
}
给栈分配空间,栈底指针指向数组首位的地址。
(3)判断顺序栈是否为空
int StackEmpty(SqStack s) {
if (s.top == s.base)
return 1;
else
return 0;
}
如果栈顶指针和栈底指针相同(指向同一位置),那么顺序栈就是空的。
(4)求顺序栈的长度
int StackLength(SqStack s) {
return s.top - s.base;
}
栈顶指针与栈底指针相减就是栈内元素的个数,即长度。
(5)清空顺序栈
int ClearStack(SqStack s) {
if (s.base)
s.top = s.base;
return 1;
}
如果栈底指针不为空的话,让栈顶指针等于栈底指针即可。
(6)销毁顺序栈
int DestoryStack(SqStack& s) {
if (s.base) {
delete s.base;
s.stacksize = 0;
s.base = s.top = NULL;
}
return 1;
}
删除栈底指针,把栈容量改为0,然后栈底指针和栈顶指针都为NULL。
(7)顺序栈的入栈
int Push(SqStack& s, int e)
{
if (s.top - s.base == s.stacksize)
return 0;
*s.top = e;
s.top++;
return 1;
}
如果栈满则报错,如果不满的话让栈顶指针指向的内容修改为e,栈顶指针向上移动。
(8)顺序栈的出栈
int Pop(SqStack& s, int& e)
{
if (s.top == s.base)
return 0;
--s.top;
e = *s.top;
return 1;
}
如果栈满则报错。栈不满,栈顶指针向下移动,用e保存出栈的数据。
示例:
int main() {
SqStack s;
InitStack(s);
for (int i = 0; i < 5; i++)
{
Push(s, i + 1);
printf("增加%d个元素,当前栈的长度为:%d\n", i + 1,StackLength(s));
}
cout << endl;
int e;
for (int i = 0; i < 4; i++)
{
Pop(s, e);
printf("弹出%d个元素,当前栈的长度为:%d\n", i + 1, StackLength(s));
}
return 0;
}
2.顺序栈简化版本
(1)顺序栈的表示
typedef struct SqStack{
int data[MaxSize];
int top=-1;
}SqStack;
直接在结构体里面分配看空间,也就是不需要初始化了。同时也不需要栈底指针,栈顶指针初始化为-1(元素的序号从0开始)。
顺序栈为空栈——top==-1
顺序栈为满栈——top==MaxSize-1
(2)顺序栈的入栈
int Push(SqStack& s, int e) {
if (s.top == MaxSize - 1) {
return 0;
}
s.top++;
s.data[s.top] = e;
return 1;
}
s.top向上移动后就代表了元素的索引。
(3)顺序栈的出栈
int Pop(SqStack& s, int& e)
{
if (s.top == -1)
return 0;
e = s.data[s.top];
s.top--;
}
s.top起索引作用。
示例:
int main() {
SqStack s;
for (int i = 0; i < 5; i++)
{
Push(s, i + 1);
printf("增加%d个元素,当前栈的长度为:%d\n", i + 1,s.top+1);
}
cout << endl;
int e;
for (int i = 0; i < 4; i++)
{
Pop(s, e);
printf("弹出%d个元素,当前栈的长度为:%d\n", i + 1, s.top+1);
}
return 0;
}
3.链栈
(1)链栈结点定义
typedef struct StackNode {
int data;
struct StackNode* next;
}StackNode,*LinkStackPtr;//栈结点和指针的定义
链栈结点和链栈指针定义方式相同(类似int 和 int*的关系),结点有数据域和指针域。
(2)链栈的定义
typedef struct LinkStack {
LinkStackPtr top;//栈顶指针
int count;//记录元素个数
}LinkStack;//栈的定义
链栈里有一个栈顶指针,还有一个计数器。
(3)链栈的初始化
int InitStack(LinkStack& s) {
//s.top=new StackNode;
s.top = NULL;
s.count = 0;
return 1;
}
注释的一句:是生成一个新结点当作栈的头结点,当然可要可不要。然后把栈顶指针置空,让计数器初始化为0。
(4)入栈
int Push(LinkStack& s, int e) {
LinkStackPtr p = new StackNode;//生成一个新结点
p->data = e;
p->next = s.top;//修改指针域
s.top = p;//修改栈顶指针
s.count++;//计数器加一
return 1;
}
链栈是从上往下遍历的,上面的结点指针域指向下面的结点。栈顶指针一直指向最上面的结点。而且对于链栈来说,基本不存在栈满的情况。
(5)出栈
int Pop(LinkStack& s, int& e) {
LinkStackPtr p;
if (s.count == 0)
return 0;
e = s.top->data;
p = s.top;
s.top = s.top->next;//移动栈顶指针
delete p;
s.count--;
return 1;
}
栈空的条件:s.count==0,新生成一个指针p指向栈顶结点,移动栈顶指针,删除p指向的结点,计数器减一。
示例:
int main() {
LinkStack s;
InitStack(s);
int n,m;
cout << "请输入要入栈元素的个数:";
cin >> n;
cout << "输入要入栈的元素:";
for (int i = 0; i < n; i++)
{
int e;
cin >> e;
Push(s, e);
}
cout << "请输入要出栈元素的个数:";
cin >> m;
for (int i = 0; i < m; i++)
{
int e;
Pop(s, e);
}
cout << "栈里剩余元素为:";
for (int i = 0; i < s.count; i++) {
printf("%d ", s.top->data);
s.top=s.top->next;
}
return 0;
}