栈:一种特殊的线性表,只允许在固定的一端进行插入和删除元素操作。我们把允许插入和删除的一端称为栈顶(top),另一端
称为栈底(bottom)。不含任何数据元素的栈称为空栈。栈是一种先入后出的线性表。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫出栈,出数据在栈顶。
在计算机系统中,栈则是一个具有以上属性的动态内存区域。程序可以将数据压入栈中,也可以将数据从栈顶弹出。在i386机器中,栈顶由称为esp的寄存器进行定位。压栈的操作使得栈顶的地址减小,弹出的操作使得栈顶的地址增大。
栈在程序的运行中有着举足轻重的作用。最重要的是栈保存了一个函数调用时所需要的维护信息,这常常称之为堆栈帧或者活动记录。堆栈帧一般包含如下几方面的信息:
1.函数的返回地址和参数。
2.临时变量:包括函数的非静态局部变量以及编译器自动生成的其他临时变量。
栈实现
1、利用顺序表实现,即使用尾插+尾删的方式实现。
2、利用链表实现,则头尾皆可以。
顺序栈的实现
顺序栈要实现扩容,则不能用数组来实现。因此可以动态申请一块内存,将栈中元素放入其中。通过动态内存申请返回的指针来以数组的形式访问栈中元素。 其次,该动态内存的大小初始时可以设置为已默认值,如果超过默认值时,可以重新申请更大的内存,从而达到扩容的目的。 最后,需要知道栈中实际元素的个数。来记录顺序表中最后一个元素所在的位置下标。以及与默认长度进行对比。
#include <stdio.h>
#include<assert.h>
#include<stdlib.h>
#define LEN 10
typedef struct statck
{
int *base; //指向栈元素空间
int size; //栈的大小
int top; //栈顶指针
}sta;
void InitStack(sta &ps) //初始化
{
ps.base = (int*)malloc(LEN * sizeof(int));
ps.top = 0;
ps.size = LEN;
}
bool Push(sta &ps, int val) //进栈
{
if (ps.top >= ps.size)//溢出
{
int* newbase = (int*)realloc(ps.base, (ps.size * 2) * sizeof(int)); //扩容
if (!newbase)
{
printf("error\n");
return false;
}
ps.base = newbase;
ps.size = ps.size * 2;
}
ps.base[ps.top] = val;
ps.top++;
return true;
}
bool Pop(sta& ps, int val)
{
if (ps.top == 0)
{
printf("statck is empty\n");
return false;
}
else
{
ps.top--;
val = ps.base[ps.top];
return true;
}
}
链式栈的实现
链式栈是通过单链表来实现的。每次入栈一个元素,向链表中添加一个节点,出栈一个元素,释放一个节点。因为栈具有“后进先出”的特点,如果每次在链表的尾部进行插入和删除,就要遍历整个链表来找到尾节点。而在头部进行插入和删除时,只需根据头指针即可找到链表的首元素结点。而无需遍历链表。所以链式栈的出,入栈通过对链表进行头删和头插来实现。
#include<stdio.h>
#include<stdlib.h>
typedef struct Node
{
int data;
struct Node* next;
}node;
//链栈的初始化
void InitStack(node** top)
{
if ((*top = (node*)malloc(sizeof(node))) == nullptr)//为头结点开辟一个存储空间
{
return;
}
(*top)->next = nullptr; //将链栈的头结点指针域置为空
}
//判断链栈是否为空
int StackEmpty(node* top)
{
if (top->next == nullptr)
{
return 1;
}
return 0;
}
//进栈操作
void PushStack(node* top, int data)
{
node* p = (node*)(malloc(sizeof(node)));
if (p == nullptr)
{
printf("内存分配失败!\n");
}
else
{
p->data = data;
p->next = top->next;
top->next = p;
}
}
//出栈操作
void PopStack(node* top, int* data)
{
node* p = top->next;
if (p == nullptr)
{
printf("栈为空!\n");
}
else
{
top->next = p->next;
*data = p->data;
free(p); //释放p指向的结点
}
}
//取栈顶元素
int GetTop(node* top, int *data)
{
node* p = top->next;
if (StackEmpty(top))
{
printf("栈为空!\n");
return -1;
}
else
{
*data = p->data;
}
return *data;
}
//求表长操作
int StackLength(node *top)
{
int count = 0;
node *p = top;
while (p->next != NULL)
{
count++;
p = p->next;
}
return count;
}
//销毁链栈
void DestoryStack(node* top)
{
node *p = top;
node *q;
while (p != nullptr)
{
q = p;
p = p->next;
free(q);
}
}
//打印栈中元素
void StackPrint(node* top)
{
node* p;
if (StackEmpty(top))
{
printf("栈为空!\n");
}
printf("栈中元素为:");
p = top;
while (p->next != nullptr)
{
p = p->next;
printf("%-3d", p->data);
}
printf("\n");
}
int main()
{
node *Ls;
int data;
InitStack(&Ls);
printf("将1,2,3,4依此入栈:\n");
PushStack(Ls, 1);
PushStack(Ls, 2);
PushStack(Ls, 3);
PushStack(Ls, 4);
StackPrint(Ls);
printf("栈的长度为:%d\n", StackLength(Ls));
printf("栈顶元素为:%d\n", GetTop(Ls, &data));
PopStack(Ls, &data);
StackPrint(Ls);
printf("栈的长度为:%d\n", StackLength(Ls));
printf("栈顶元素为:%d\n", GetTop(Ls, &data));
DestoryStack(Ls);
return 0;
}