数据结构 --- 栈

栈 --- stack

前言

栈是一个特殊的线性表,遵循一个先进后出的特性,即操作数据(入栈,出栈)只能从栈顶操作,栈底是一个封口的结构。既然是线性表从逻辑结构上是线性的,物理结构上取决于底层实现的结构,若是顺序栈(底层为数组),则是线性的,若是链栈,则是非线性的,本次实现的栈为顺序栈,对比链栈空间更小:

对比上述两种栈的实现结构,进行入栈出栈操作时,两种结构的时间复杂度都为O(1),但是在进行入栈操作时,假设type是int类型,那么数组结构就只增加4个字节,而链表结构会增加8个或者12个字节,对比而得顺序栈更好,当然也不是一定不能使用链表实现。

同时本次实现栈使用C语言实现。

一、栈结构

经由前文使用数组定义栈结构,有三个属性,一个指向栈的指针arr,一个标记栈顶位置和栈实际大小的top(其实也就是顺序表的size)是有效数据的下一个位置,以及一个空间容量capacity。

c 复制代码
//定义栈结构
typedef int STDataType;   // 方便更改栈存储数据的类型
typedef struct Stack
{
	STDataType* arr; //指向栈的指针
	int top;         //栈顶位置和栈实际大小
	int capacity;    //空间容量
}ST;

二、相关方法

1.初始化

初始化是将栈初始化成一个空栈,即栈底层数组置为NULL,将top和capacity等于0。

c 复制代码
//初始化
void StackInit(ST* ps)
{
	ps->arr = NULL;
	ps->top = ps->capacity = 0;
}

2.入栈

入栈操作四步,首先判断传递过来的参数栈是否不为空,不为空才能进行入栈操作,第二步,判断是否需要扩容,当top == capacity时进行扩容操作(两种情况,一为空栈,二为栈满),使用realloc进行扩容操作,第三步,更新数据,当扩容完成后,需要将扩容后的数组和空间大小更新回arr和capacity,最后再在top栈顶位置插入数据,top再加加;

当空间充足时直接进行最后的插入操作。

c 复制代码
//入栈
void StackPush(ST* ps, STDataType x)
{
	assert(ps);   //ps不能传空

	//首先判断栈空间是否需要增容 --- 没有空间或者空间已满
	if (ps->top == ps->capacity)
	{
	    // 增容
		int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		STDataType* temp = (STDataType*)realloc(ps->arr, newcapacity * sizeof(STDataType));
		if (temp == NULL)
		{
			perror("realloc");
			exit(1);
		}
		ps->arr = temp;
		ps->capacity = newcapacity;
	}
	
	//空间充足 --- top位置入栈,入栈完成top+1
	ps->arr[ps->top++] = x;
}

3.出栈

出栈首先需要断言传递过来的参数栈不为空,并且栈内需存在元素方可进行出栈操作,其次直接减减top栈顶位置即可。

c 复制代码
//出栈 --- 要改变top位置 
void StackPop(ST* ps)
{
    //assert(ps && ps->top);
	assert(ps && !StackEmpty(ps));   //ps不能传空,top==0不能再出栈

	--ps->top;
}

4.判空

当栈为空时,返回true,不为空时返回false。

c 复制代码
//判定栈是否为空
bool StackEmpty(ST* ps)
{
	assert(ps);   //ps不能传空
	return ps->top == 0;
}

5.获取栈顶元素

获取栈顶元素即获取top位置的元素,并且只是读取元素而不是出栈,故top大小不会改变。

c 复制代码
//获取栈顶元素 --- top位置不用改变
STDataType StackTop(ST* ps)
{
	assert(ps);   //ps不能传空

	return ps->arr[ps->top-1];
}

6.获取栈大小

c 复制代码
//获取栈中有效数据个数
int StackGetSize(ST* ps)
{
	assert(ps);   //ps不能传空

	return ps->top;
}

7.销毁

销毁栈空间即将数组置为空,top和capacity等于0,也就是恢复至空栈状态,当然数组若已为NULL了,则无需置空。

c 复制代码
//销毁
void StackDestroy(ST* ps)
{
	assert(ps);
	if (ps->arr != NULL)
	{
		free(ps->arr);
		ps->arr = NULL;
	}
	ps->top = ps->capacity = 0;
}