栈是一种仅在一端进行操作的数据接口,它遵循先入后出的规则。栈可以用前面学过的链表表示也可以使用顺序表来进行实现。
因为栈通常最常用的操作是在尾部进行插入和删除,故利用顺序表来实现栈再合适不过了!(时间复杂度较低,不需要遍历来寻找最后一个节点)。
各种接口的实现原理也与顺序表基本相同。
首先,定义栈的基本结构体
typedef int DtaType;
typedef struct Stack{
DataType *a; //指向栈中元素的指针
int capacity; //栈的容量
int top; //栈顶元素,与顺序表的size一个效果
}
我们来看栈的初始化接口
void InitStack(Stack *s)
{
s->a=NULL;
s->capacity=s->top=0;
}
栈的的入栈与出栈都是在尾部进行的
栈的入栈(尾插)
void StackPushBack(Stack *s,DataType x)
{//尾插虽简单 ,但是要在插入时检查栈的空间,还有没有剩余的空间支持插入,不支持时要进行扩容
if(s->top==s->capacity)
{
int newcapapcity=s->capacity==0?10:2*s->capacity;
s->a=(DataType *)realloc(s->a,sizeof(DataType)*newcapacity) //realloc是在原基础进行扩容,这一点比malloc方便很多。
s->capacity=newcapacity;
}
s->a[s->top]=x;
s->top++;
}
栈的出栈(尾删)
void StackPopBack(Stack *s)
{
s->top--; //思想参考顺序表的尾删
}
栈的判空
void IsEmpty(Stack *s)
{
if(s->top=0)
{
printf(“该栈为空栈!!!”);
}
else
return;
}
这是挨个打印栈中元素的接口
void StackPrint(Stack *s)
{
while (s->top)
{
printf("%d->", s->a[s->top-1]);
s->top--;
}
}
还有一点,别把 数据结构里的栈与堆与内存中的栈与堆弄混了。两者虽然名字相同,但却是两种截然不同的东西!
内存中的栈区处于相对较高的地址以地址的增长方向为上的话,栈地址是向下增长的。栈中分配局部变量空间。堆区是向上增长的用于分配程序猿申请的内存空间。另外还有静态区是分配静态变量,全局变量空间的;仅仅读区是分配常量和程序代码空间的;以及其它一些分区。
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int DataType;
typedef struct Stack{
DataType *a;
int capacity;
int top;
}Stack;
//栈的初始化
void StackInit(Stack *s)
{
s->a = NULL;
s->capacity = s->top = 0;
}
//销毁
void StackDestroy(Stack *s)
{
free(s->a);
s->a = NULL;
s->capacity = s->top = 0;
}
//尾插
void StackPushBack(Stack *s, DataType x)
{
//先检查容量是否支持
if (s->capacity == s->top)
{
int newcapacity = s->capacity == 0 ? 10 : 2 * s->capacity;
s->a = realloc(s->a, sizeof(DataType)*newcapacity);
s->capacity = newcapacity;
}
s->a[s->top] = x;
s->top++;
}
//出栈
void StackPop(Stack *s)
{
s->top--;
}
//判空
void IsEmpty(Stack *s)
{
if (s->top == 0)
{
return 1;
}
return 0;
}
//判满
void IsFull(Stack *s)
{
if (s->top == s->capacity)
{
return 1;
}
return 0;
}
//打印接口
void StackPrint(Stack *s)
{
while (s->top)
{
printf("%d->", s->a[s->top - 1]);
s->top--;
}
}