【栈和队列】数组栈详解(C语言版)

目录

引言

一、定义 

二、初始化

三、销毁

四、插入

五、删除

六、获取栈顶元素

七、判空

八、已存放数据数

结尾


ID:HL_5461

引言

(前方超短提示~这篇真没啥可说的……)

先来看看栈是什么。

栈是一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。

后进:

fbde57c59d82458e97764d995847d452.png

先出:

d89be6bb8f4845f0966f11486d48d495.png


一、定义 

本篇我们选择使用数组作为栈,这又回到了之前所讲过的顺序表,不太理解的可以去翻我之前写的博客:【线性表】顺序表详解(C语言版)_是兰兰呀~的博客-CSDN博客

在实现栈的过程中,我们使用动态的顺序表,这样方便对其进行扩容。不过与顺序表定义不同的一点是,我们将不再使用size,而是改用top,top代表栈顶元素下标,其余,指针a,空间capacity都不变化。

前面我们说了,top代表栈顶元素下标,这样就面临一个问题:下标指向哪比较合适?

83ade30d7e4f4544a6b0b5b8a6ec653c.png

如图,我们该选择top1还是top2作为top呢?这其实就是一个习惯问题。当我们选择top1时,栈内无元素时top等于0,此时top与顺序表的size含义相同,代表栈内元素个数,a[top]为栈顶元素的后一位;当我们选择top2时,a[top]表示栈顶元素,这时要注意,当栈内无元素时top为-1。

一方面为了和顺序表保持一致,另一方面也是个人习惯,我选择top1作为top。

我们将存储的数据类型的指针a,栈顶元素下标top,以及表示当前开辟的空间大小的capicity封装到一个结构体中,如下图所示:

b63a17e9d858412d8c25e167587a44b9.png

 

typedef int STDataType;//定义STDataType为int,方便以后修改存储的数据类型

typedef struct Stack
{
	STDataType* a;//动态开辟的空间指针
	int top;//栈顶元素下标
	int capacity;//空间大小
}ST;

二、初始化

在顺序表中,我们在初始化时就顺便开辟了四个大小为SLDataType的空间,但在栈中,我们将开辟空间统一放到插入中去,初始化只做最简单的置空指针以及将top和capacity置0。

void STInit(ST* ps)
{
	assert(ps);//ps不为空指针

	ps->a = NULL;//数组指针置空
	ps->top = 0;//栈顶元素下标为0
	ps->capacity = 0;//空间大小为0
}

三、销毁

栈的销毁和顺序表一样,三步走:释放空间、指针置空、变量置零。OK,讲完,上代码~

void STDestroy(ST* ps)
{
	assert(ps);//ps不为空指针

	free(ps->a);//释放数组

	ps->a = NULL;//置空数组指针
	ps->top = 0;//栈顶元素下标置0
	ps->capacity = 0;//空间大小置0
}

四、插入

栈的插入就是顺序表的尾插,由于栈只允许在固定的一端进行插入和删除元素操作的特点,它没有诸如头插、中间插入等花里胡哨的东西。同样,也是因为这个,我们不需要跟顺序表一样特意写一个容量判断的函数了,将这部分功能直接放到插入里面也是一样的。

e0c0e481d1fb42089d9e667c000f7a07.png

我们先判断栈空栈满,当top == capacity时栈即为满,栈满需扩容。

e777a569651148b999f2ad0dc4f0d87d.png

扩容其实并不难,我们照例让空间变为原来的两倍,但由于我们并没有像之前一样初始化分配4个空间,所以这里存在capacity为0的特殊情况:0*0 = 0,。我们还需有一个对capacity的判断,当它为0时,为它分配4个STDataType大小的空间,不为0时令新空间大小为原先的二倍。

e24b774c46de4fe29307c9cf529bdcf6.png

将x值放入新top所在位置,并将top++。 

void STPush(ST* ps, STDataType x)
{
	assert(ps);

	if (ps->top == ps->capacity)//栈满
	{
		int NewCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;//原空间为0令新空间大小为4,否则扩为2倍
		STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * NewCapacity);//为原空间扩容

		if (tmp == NULL)//扩容失败
		{
			perror("STPush");//打印失败
			exit(-1);//程序以非正常形式结束
		}
		//扩容成功
		ps->a = tmp;//将扩容后的地址赋给a
		ps->capacity = NewCapacity;//修改capacity为新大小
	}

	ps->a[ps->top] = x;//将x放入栈顶
	ps->top++;//栈顶元素下标加1
}

五、删除

so easy~这个不讲了哈~就是尾删,直接top--就OK了,注意断言栈不为空就行了。

void STPop(ST* ps)
{
	assert(ps);//ps不为空
	assert(ps->top > 0);//栈不为空

	ps->top--;//栈顶元素下标少1
}

六、获取栈顶元素

为了体现栈后进先出的特性,栈一般是没有打印、查找等操作的,但有个获取栈顶元素的操作,这个操作一般和删除连用,读一个删一个,这样就可以依次读出后来进入的元素啦~

当然这个操作本身还是超简单的,直接返回a[top-1]即栈顶元素就好。

STDataType STTop(ST* ps)
{
	assert(ps);//ps不为空
	assert(ps->top > 0);//栈不为空

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

七、判空

我其实挺纠结这个要不要放,真的太简单了,但还是争取做到面面俱到吧……

这个函数的返回值我们设为bool类型,空返回真,非空返回假。

bool STEmpty(ST* ps)
{
	assert(ps);//ps不为空

	return ps->top == 0;//top为0则空,不为0则非空
}

八、已存放数据数

正如我们开头讲的,这些代码的top其实就相当于顺序表里的size,代表的就是已存放的数据数,so,直接返回top值就行。

int STSize(ST* ps)
{
	assert(ps);//ps不为空

	return ps->top;//top即为已存放数据数
}

结尾

emmm…目录看着似乎挺多操作,但这篇真没啥可说的,所以,就这样叭~下次再见~

这是本篇代码码云链接:

class_c: 课上要认真鸭~ - Gitee.com

若有错误,欢迎大家批评斧正! 

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是兰兰呀~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值