当前位置:   article > 正文

【数据结构】栈_取栈顶元素操作

取栈顶元素操作

栈是什么

栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。

  • 进行数据插入和删除操作的一端 称为栈顶,另一端称为栈底。
  • 栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
  • 压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
  • 出栈:栈的删除操作叫做出栈。出数据也在栈顶。

栈也是一种线性表,是一种特殊的数据结构,我们可以用我们前面所学的知识来实现栈

我们之前学习的顺序表和链表只是单纯的存储数据,并可以做到增删查改的作用,而栈除了存储数据还要达到后进先出的性质

**[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xaThLV3d-1684251023742)(C:\Users\李诗琦\AppData\Roaming\Typora\typora-user-images\image-20230515161041163.png)]**

  • 如图我们假设,数据入栈完成后再出,即先存储1 2 3 4后再出数据,按照后进先出原则,我们的出栈顺序就是4 3 2 1
  • 倘若不要求入栈完成再出,就有很多种,如1 2 3 4,即入一个出一个。3 2 4 1即入把3 2出了后再入
  • 但没有3 1 2 4这样的顺序,2没有可能比1先出。

助力理解:

1.一个栈的初始状态为空。现将元素12345、A、B、C、D、E依次入栈,然后再依次出栈,则元素出
栈的顺序是( B)。
A 12345ABCDE
B EDCBA54321
C ABCDE12345
D 54321EDCBA
    
2.若进栈序列为 1,2,3,4 ,进栈过程中可以出栈,则下列不可能的一个出栈序列是(C)
A 1,4,3,2
B 2,3,4,1
C 3,1,4,2
D 3,4,2,1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

接下来就是实现栈了,有2种方式实现

  • 数组栈
  • 链式栈

这里我们用数组来实现栈会更方便一点,数组的高数缓存命中更高,并且结构很符合栈的需求,尾部就可以当栈顶,尾插尾删即可

在这里插入图片描述

如果选链表实现的话,我们的的尾删就要遍历链表找到前一个太慢,只能将头当成栈顶,进行头删头插

定义结构体

typedef int DataType;
typedef struct stack
{
	DataType* p;
	int top;
	int num;
}st;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 我们在写较长代码的时候,我们为了方便可以将数据类型typedef一下,比如这里的int起别名叫DataType,当我们下次针对char类型的时候,一改即可。
  • 栈的实现需要一个指针,指向我们开辟的数组的起始位置。
  • top表示栈顶位置,可以理解为开辟空间里面的有效个数。
  • num表示现在空间的大小。

初始化

void stinit(st* pst)
{
	assert(pst);

	pst->p = NULL;
	pst->top = 0;		//这里top也可以赋值-1
	pst->num = 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这是我们的一种初始化方式,即先不开辟空间,这里我们重点讲top的赋值

  • 当 top = 0 的时候

在这里插入图片描述

我们的top是指向数据的下一个位置,因为我们是先插入数据,再让top++

在这里插入图片描述

如图,top先指向0,插入数据后top++,即top指向的是栈顶元素的下一个位置

  • 当 top = -1 的时候

    与上面相似,不够我们是让top++,再插入数据,这个时候top就指向栈顶元素

我们一定要分清楚自己想让top指向栈顶元素还是栈顶元素的下一个,不然你想指向栈顶元素,却赋值为0,那这就说明这个时候栈里面就已经有数据呢,但你还没插入。

要重视top的赋值,不然后面的所以操作都会收到影响,这里使用 top = 0 的情况

销毁空间

void stdestroy(st* pst)
{
	assert(pst);

	free(pst->p);
	pst->p == NULL;
	pst->num = 0;
	pst->top = 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

值得注意的是,这里的free是free全部开辟的空间,数组空间连续,并不是你的链表一个一个释放

入栈

我们的栈没有头和尾的概念,所以我们的命名就是stpush

void stpush(st* pst, DataType x)
{
	assert(pst);
	if (pst->top == pst->num)
	{
		int newnum = pst->top == 0 ? 4 : pst->num * 2;
		DataType* newp = (DataType*)realloc(pst->p, sizeof(DataType) * newnum);
		if (!newp)
		{
			perror("realloc");
			return;
		}
		pst->p = newp;
		pst->num = newnum;
	}
	pst->p[pst->top] = x;
	pst->top++;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

值得注意的是,我们这里的初始化不开辟空间和这里呼应上了

int newnum = pst->top == 0 ? 4 : pst->num * 2;
DataType* newp = (DataType*)realloc(pst->p, sizeof(DataType) * newnum);
  • 1
  • 2

我们的newp是赋值给pst->p的不要把类型写出st*了

我们的

这是一种写法,推荐学习

在这里插入图片描述

在这里插入图片描述

这里的memblock指针为NULL的时候,realloc表现如同malloc一样

我们并不需要单独写一个函数去扩容,因为复用的函数很少,这个push函数把扩容也包括了

出栈

我们只需要让top–即可

void stpop(st* pst)
{
	assert(pst);
	assert(!stempty(pst));

	pst->top--;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

注意,为了代码的可读性,我们推荐写上一个判空的函数STEmpty

获取栈顶元素

我们为什么不在主函数中直接用下标访问呢?

如:
void test()
{
    st st;
    st.p[st.top];
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

​ 因为这样对使用者的需求过大,使用者不知道你的top是指向哪的,当top为0的时候,使用者可能会当成下标来访问了,打印出随机值来,当top为-1的时候,使用者会感到疑惑

我们用函数来实现获取栈顶元素

DataType sttop(st* pst)
{
	assert(pst);

	return pst->p[pst->top - 1];
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

判空函数

bool stempty(st* pst)
{
	assert(pst);

	/*if (!pst->top)
	{
		return true;
	}
	else
	{
		return false;
	}*/

	return pst->top == 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

我们要学习一下,这里是一个比较操作符,等于0就是真,反之为假

获取栈中元素个数

DataType stsize(st* pst)
{
	assert(pst);
	return pst->top;
}
  • 1
  • 2
  • 3
  • 4
  • 5

打印元素

  • 我们不能自己创造一个print函数来打印栈中的元素,因为栈的后进先出的性质,我们就不能随机访问里面的元元素了
  • 我们只能出一个访问一个
while (!stempty(&st))
{
	printf("%d ", sttop(&st));
	stpop(&st);
}
  • 1
  • 2
  • 3
  • 4
  • 5

真,反之为假

获取栈中元素个数

DataType stsize(st* pst)
{
	assert(pst);
	return pst->top;
}
  • 1
  • 2
  • 3
  • 4
  • 5

打印元素

  • 我们不能自己创造一个print函数来打印栈中的元素,因为栈的后进先出的性质,我们就不能随机访问里面的元元素了
  • 我们只能出一个访问一个
while (!stempty(&st))
{
	printf("%d ", sttop(&st));
	stpop(&st);
}
  • 1
  • 2
  • 3
  • 4
  • 5
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/518618
推荐阅读
相关标签
  

闽ICP备14008679号