栈的介绍
栈的概念
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端
称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫叫做出栈。出数据也在栈顶。
栈的实现
由栈的定义可知:栈要遵循后进先出LIFO(Last In First Out)的原则。所以在设计实现栈时,用顺序表即数组来实现栈是十分合适的(数组对尾部操作方便)
栈的结构
采用动态数组来实现栈。其结构有一个指向数组的指针,记录栈顶位置的top,检查容量的capacity
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;//栈顶
int capacity;//容量
}ST;
栈的初始化
将所有成员都初始化置为0。要改变Stack这个结构体就要将其地址传过来,所以用assert断言一下,防止传错。
void STInit(ST* pst)
{
assert(pst);
pst->a = NULL;
pst->capacity = pst->top = 0;
}
插入数据——入栈
数据入栈就要检查空间是否足够,采用realloc以二倍的速度来动态扩容。
在确定空间足够的情况下,将数据插入数组即可
void STPush(ST* pst, STDataType x)
{
assert(pst);
if (pst->capacity == pst->top)//检查剩余容量
{
int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
ST* tmp = (ST*)realloc(pst->a, sizeof(STDataType ) * newcapacity);
if (tmp == NULL)
{
perror("realloc failed");
return;
}
pst->capacity = newcapacity;
pst->a = tmp;
tmp = NULL;
}
pst->a[pst->top++] = x;
}
需要注意malloc开辟的是数组a的空间,而不是开辟栈的空间
注意扩容后要将capacity更新。
插入数据后要将栈顶位置上移即top++
删除数据——出栈
数据出栈要检查是否还有数据,随后将栈顶位置top–完成出栈,无需对原有数据进行修改,因为当有新数据再次入栈时就会覆盖原有数据
void STPop(ST* pst)
{
assert(pst);
assert(!STEmpty(pst));
pst->a[pst->top--];
}
获取栈的元素个数
top即是栈顶位置也是元素个数,返回就好了
int STSize(ST* pst)
{
assert(pst);
return pst->top;
}
获取栈的元素
要注意top是栈顶位置,需要减一来访问栈顶元素
STDataType STTop(ST* pst)
{
assert(pst);
assert(!STEmpty(pst));
return pst->a[pst->top - 1];
}
判断栈是否为空
该函数返回值为布尔类型,该类型变量取值为true或false。
一般通过assert来检查是否为空(assert(!STEmpty(pst));)。当STEmpty返回值为假时,说明还有数据,!STEmpty(pst)即为真,不会引起断言。当STEmpty返回值为真时,说明没有数据了,!STEmpty(pst)即为假,引起断言
bool STEmpty(ST* pst)
{
assert(pst);
return pst->top == 0;
}
assert断言的是假。这一段可能有点绕,如果不清晰还需多看几遍
栈的销毁
栈的销毁也十分简单,只需要把realloc在堆区开辟的空间free掉,并将全部置为0即可。
栈的数据打印也与以往有些不同,具体在下面完整代码的test文件中
void STDestroy(ST* pst)
{
assert(pst);
free(pst->a);
pst->a = NULL;
pst->capacity = pst->top = 0;
}
完整代码
按我的习惯依旧分成了三个文件
Stack.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;//栈顶
int capacity;//容量
}ST;
void STInit(ST* pst);//初始化
void STDestroy(ST* pst);//销毁
void STPush(ST* pst, STDataType x);//入栈
void STPop(ST* pst);//出栈
int STSize(ST* pst);//获取元素个数
STDataType STTop(ST* pst);//获取栈顶元素
bool STEmpty(ST* pst);//判空
Stack.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Stack.h"
void STInit(ST* pst)
{
assert(pst);
pst->a = NULL;
pst->capacity = pst->top = 0;
}
void STDestroy(ST* pst)
{
assert(pst);
free(pst->a);
pst->a = NULL;
pst->capacity = pst->top = 0;
}
void STPush(ST* pst, STDataType x)
{
assert(pst);
if (pst->capacity == pst->top)
{
int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
ST* tmp = (ST*)realloc(pst->a, sizeof(STDataType ) * newcapacity);
if (tmp == NULL)
{
perror("realloc failed");
return;
}
pst->capacity = newcapacity;
pst->a = tmp;
tmp = NULL;
}
pst->a[pst->top++] = x;
}
void STPop(ST* pst)
{
assert(pst);
assert(!STEmpty(pst));
pst->a[pst->top--];
}
int STSize(ST* pst)
{
assert(pst);
return pst->top;
}
STDataType STTop(ST* pst)
{
assert(pst);
assert(!STEmpty(pst));
return pst->a[pst->top - 1];
}
bool STEmpty(ST* pst)
{
assert(pst);
return pst->top == 0;
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Stack.h"
void STTest()
{
ST st;
STInit(&st);
/*STPush(&st, 1);
STPush(&st, 2);
STPop(&st);
STPush(&st, 3);
STPush(&st, 4);
printf("Size:%d\n", STSize(&st));
printf("Top:%d\n", STTop(&st));
while (!STEmpty(&st))//栈的数据打印
{
STDataType top = STTop(&st);
STPop(&st);
printf("%d ", top);
}*/
STDestroy(&st);
}
int main()
{
STTest();
return 0;
}