0
点赞
收藏
分享

微信扫一扫

以前以为去流量大的部门是好事,能学技术,现在才知道,流量大的部门狗都不去!晚上9点才下班,一天到晚都是监控告警!...

栖桐 2023-05-17 阅读 96

文章目录

栈的概念及结构

  • 栈具有以下几个特点:
    1. 后进先出(LIFO):最后进入栈的元素最先被访问,而最先进入栈的元素最后被访问。
    2. 只允许在一端进行插入和删除操作:栈通常只允许在栈顶进行插入和删除操作,而不允许在其他位置进行操作。
    3. 栈顶指针:栈顶指针指向栈顶元素,它随着元素的插入和删除而改变。

  • 栈的结构
    对于栈来讲,理论上线性表的操作特性它都具备,可由于它的特殊性,所以针对它在操作上会有些变化。特别是插入和删除操作.那栈的结构用数组还是链表实现?
  • 数组实现的缺点

  • 用链表实现的优点
  • 链表实现的缺点
  • 用链表还是用数组结构实现这个问题的答案取决于具体的应用场景和需求,本章节我们使用数组存储结构来实现.
    栈数组存储结构
typedef int STDateType; // 定义栈元素类型
typedef struct StackNode
{
	STDateType * a;  // 数组指针
	int top;		 // 栈顶
	int capacity;	// 栈的容量
}st;

栈接口的实现

栈的初始化

  • 这里讲解下有的人是把top给成-1的,栈顶指针 top 被初始化为 -1,表示栈中没有任何元素。当向栈中插入第一个元素时,我们需要将 top 的值加 1,然后将该元素存储在数组中 top 所指向的位置。此时,top 的值为 0,表示栈中有一个元素。因此,栈中有一个元素是因为插入了第一个元素。所以这里要取分一下.top给成0还是-1,根据场景应用给成多少。
void STInit(ST* pst)
{
	assert(pst);
	pst->a = NULL;	
	pst->top = 0;   // top 指向栈顶数据的下一个位置

	pst->capacity = 0;
}

入栈

  • 入栈步骤
    1. 首先判断栈是否已满,即栈顶指针 top 是否等于栈的容量 capacity。如果栈已满,则需要扩容,这里的扩容策略是将栈的容量翻倍,如果栈的容量为 0,则新分配的容量为 4,将扩容后的数组 tmp 赋值给原来的数组 pst->a,并更新栈的容量为 newCapacity。
    2. 将元素 x 存储在栈顶指针 top 所指向的位置,然后将栈顶指针 top 加 1,指向下一个空闲位置,以便下一次入栈操作。
void STPush(ST* pst, STDataType x)
{
	if (pst->top == pst->capacity) //判断栈是否已满
	{
		int newCapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(pst->a, newCapacity * sizeof(STDataType));//扩容
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}

		pst->a = tmp; //赋值给原来的数组
		pst->capacity = newCapacity; //更新栈的容量
	}

	pst->a[pst->top] = x; //入栈
	pst->top++; //+1 指向下一个空闲位置
}

出栈

  • 判断栈中是否存在元素,如存在我们将栈顶指针 top 减一,即 pst->top–,表示将栈顶元素弹出。
void STPop(ST* pst)
{
	assert(pst); //断言判断是否指针为空
	assert(!STEmpty(pst)); //判断栈中是否存在元素

	pst->top--; //将栈顶元素弹出。
}

获取栈顶元素

  • 首先确保栈不为空,如不为空返回栈顶元素的值,即数组 a 中下标为 top - 1 的元素。
STDataType STTop(ST* pst)
{
	assert(pst);  //断言判断是否指针为空
	assert(!STEmpty(pst)); //判断栈中是否存在元素

	return pst->a[pst->top - 1]; //返回栈顶元素的值
}

判断栈是否为空

  • 如果栈顶值为0,就代表栈为空.返回真,反之返回假.
bool STEmpty(ST* pst)
{
	assert(pst);  //断言判断是否指针为空
	return pst->top == 0; //判断是否为空
}

获取栈中有效元素个数

  • 该代码没有什么可说的…直接看吧
int STSize(ST* pst)
{
	assert(pst);   //断言判断是否指针为空

	return pst->top; //返回栈的元素个数
}

栈的销毁

  • 当我们不打算使用这个栈时,我们需要把它销毁,其实也就是在内存中将它释放掉,以便于留出空间给其他程序或软件使用。 我们只需要把栈的数组空间释放,避免内存泄漏。同时将指向数组的指针 a 置为 NULL,避免出现野指针。最后,将栈的容量 capacity 和栈顶指针 top 置为 0,表示栈已经被销毁。
void STDestroy(ST* pst)
{
	assert(pst); //断言判断是否指针为空

	free(pst->a); //函数释放栈的数组空间
	pst->a = NULL; //置为NULL,避免出现野指针
	pst->top = pst->capacity = 0;  //将栈的容量 capacity 和栈顶指针 top 置为 0
}

总结

  • 栈是一种简单但非常有用的数据结构,掌握它的基本概念、操作和实现方式对于编程学习和刷题,后面的面试都非常重要。
举报
0 条评论