数据结构之栈

目录

一 .概念以及结构

二 . 功能实现

2.1基本数据管理

2.2基本功能

2.2.1初始化

2.2.2销毁

2.2.3入栈

2.2.4出栈

2.2.5获取栈顶元素

2.2.6获取栈中有效元素个数

2.2.7检测栈是否为空


一 .概念以及结构

栈是顺序表和链表的连续,一种类似的结构,但也有独特的性质.

栈是一种特殊的线性表,在顺序表和链表,可以在任意位置进行插入删除.而栈只允许在固定的一端进行插入删除.对进行插入删除的一端称为:栈顶,另一端称为:栈底。栈中的数据遵循后进先出的原则,只能在栈顶进行出数据和入数据,插入叫压栈,删除叫出栈。
可以把栈想象成一个弹夹,先压进去的子弹后打出去,后后压进去的子弹先打出去.


如何实现栈,有两种方式来实现栈,分别为:数组栈、链式栈

对于用数组,栈底等于头,也可以说下标为0,栈顶等于尾

对于用双向链表,栈顶可以是尾节点,也可以是头节点。用单链表就不一样了,如果继续用尾节点作为栈顶,那么就导致尾插很方便,而尾删就十分麻烦了,所以栈顶只能是头节点

综合考虑来看,用数组来实现栈是比较方便的,对于需要扩容这方面其实影响不大,需要很久才会扩容一次影响很小。而且对于计算机来说,读取一次数组栈,就能读取到后续的数据。如果要从链表中选一个,最好的还是单链表。

所以接下来选用数组栈进行实现

二 . 功能实现

2.1基本数据管理

实现数组栈也是多个结构,需要用到结构体来管理。

typedef int STDataType;

typedef struct Stack
{
	STDataType* a;
	STDataType top;                 //标识栈顶位置的
	STDataType capacity;
}ST;

这里定义的top就是用来表示栈顶位置,capacity就是用来扩容。

2.2基本功能

2.2.1初始化

首先进行断言,确保结构体不为空.接着可以选择将a置为空,容量为0.方便之后的扩容.最后才是栈最重要的点,关于栈顶top是什么?可能会想当然的将top设置为0.那么来看看会发生什么.

因为要把栈置为空,所以将top为0.当插入了一个数据后,top为了继续指向栈顶,top依旧为0.这就出现了冲突.当看到top等于0的时候,就无法判断是一个元素还是空

所以结合上述问题,当栈为空时置为0,有元素插入时,变为1.

也可以当栈为空时top设置为-1,当有元素插入后,变为0.top == 1指向栈顶元素的下一个位置

void STInit(ST* pst)
{
	assert(pst);

	pst->a = NULL;
	pst->capacity = 0;
	pst->top = 0;
}

 

2.2.2销毁

void STDestroy(ST* pst)
{
	assert(pst);
	free(pst->a);				//释放
	pst->a = NULL;				//置空
	pst->top = pst->capacity = 0;
}

2.2.3入栈

对于初始化提到的两种解决栈顶的方法,对应到插入后写法需要改变.

当top == -1时,需要对top先自增后赋值.

当top == 0时,需要先赋值再自增

//top 为 0时
void STPush(ST* pst , STDataType x)
{
	assert(pst);

	if (pst->top == pst->capacity)
	{
		int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
		STDataType* tmp = realloc(pst->a, sizeof(STDataType) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		pst->a = tmp;
		pst->capacity = newcapacity;
	}
	pst->a[pst->top] = x;
	pst->top++;
}

 当top == -1时,只需要将最后两行代码交换位置即可.

2.2.4出栈

出栈就很简单了,只需要将top自减即可,但也要保证top不为0.

void STPop(ST* pst)
{
	assert(pst);
	assert(pst->top>0);

	pst->top--;
}

2.2.5获取栈顶元素

只需要设定返回值为top-1,为栈顶元素的下一个.

STDataType STTop(ST* pst)
{
	assert(pst);

	assert(pst->top > 0);
	return pst->a[pst->top - 1];
}

2.2.6获取栈中有效元素个数

同样,当top指向栈顶元素,那么等于-1就为空;当top指向栈顶元素的下一个位置,那么等于0就为空

bool STEmpty(ST* pst)
{
	assert(pst);
	
	if (pst->top == 0)
	{
		return true;
	}
	else
	{
		return false;
	}

}

也有更简洁的写法,直接返回判断值即可,不需要写if判断.

	return pst->top == 0;

2.2.7检测栈是否为空

同理,当top指向栈顶元素,那么等于+1就是个数;当top指向栈顶元素的下一个位置,那么top等于个数

int STSize(ST* pst)
{
	assert(pst);
	return pst->top;
}

2.2输出栈元素

栈与顺序表,单链表不同,需要严格按照规定来进行打印,通过循环判断栈是否为空来进行打印,打印后再出栈一个,继续打印.之所以这样是必须遵循栈的先进后出

	while (!STEmpty(&s))
	{
		printf("%d ", STTop(&s));		//获取栈顶并打印
		STPop(&s);						//移除栈顶元素,打印下一个
	}
	printf("/n");

那么思考一下,当以12345入栈后,出栈一定是54321?答案是 不一定.来实验一下:

可以看到,其实并不是按照之前所想的那样,因为当5和4进栈的时候,3已经出栈了,不能和3相比,只能跟在栈里的数据相比,所以栈的后进先出是相对的.所以入栈顺序和出栈顺序是一对多的关系,入栈顺序只有一种;而出栈顺序则有很多种.但出栈顺序也不是任何种类都行

若进栈序列为 1,2,3,4 ,进栈过程中可以出栈,则下列不可能的一个出栈序列是()

(A) 1,4,3,2        (B) 2,3,4,1        (C) 3,1,4,2        (D) 3,4,2,1

做这个题只需要动手画一下顺序,推导一下即可得到答案

A: 入1出1,剩下的依次入栈

B: 入1,入2出2,入3出3,入4出4.

C:无法实现

D:入12,再入34出34

所以答案选C.

栈的知识点就到这里,后续会有关于应用栈的OJ题目 

  • 20
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值