数据结构初级<栈>

本文已收录至《数据结构(C/C++语言)》专栏,欢迎大家 点赞 + 收藏 + 关注 ! 

数据结构初级<栈>_第1张图片


目录

前言 

正文

栈的数据结构

栈的接口函数

栈的实现

栈的初始化函数

入栈函数

出栈函数

获取栈顶元素函数

获取栈元素个数函数

检查栈空函数

栈销毁函数

总结


前言 

 前面我们介绍了线性表的两种数据结构顺序结构和链式结构,这两种结构各有优劣,但是今天我们还有另一种数据结构,他是基于线性表衍生出来的特殊线性表,那就是“栈”,关于栈大家可能比较陌生,我们计算机程序在内存上运行时就会有许多栈帧,学完了这一节,大家对栈就会有一定的了解。

数据结构初级<栈>_第2张图片


正文

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

栈的操作:

压栈:栈的插入操作叫做进栈/压栈/入栈入数据在栈顶

出栈:栈的删除操作叫做出栈出数据也在栈顶

总而言之,栈的增删查改操作只能在栈顶进行!

栈的数据结构


栈的实现一般可以使用顺序表(数组)或者链表实现,相对而言顺序表的结构实现更优一些。因为数组在尾上插入数据的代价比较小。我们总是取最优解进行实现,有兴趣的小伙伴可以尝试实现链式的栈!


// 支持动态增长的顺序栈
typedef int STDataType;
typedef struct Stack
{
	STDataType* _a;//空间指针
	int _top;		// 栈顶
	int _capacity;  // 容量 
}Stack;

栈的接口函数


//动态顺序栈

// 初始化栈 
void StackInit(Stack* ps);

// 入栈 
void StackPush(Stack* ps, STDataType data);

// 出栈 
void StackPop(Stack* ps);

// 获取栈顶元素 
STDataType StackTop(Stack* ps);

// 获取栈中有效元素个数 
int StackSize(Stack* ps);

// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
int StackEmpty(Stack* ps);

// 销毁栈 
void StackDestroy(Stack* ps);

栈的实现


对于栈,分为栈顶和栈底,可以理解为数组的首地址和数组的最后一个元素地址。

数据结构初级<栈>_第3张图片


栈的初始化函数

同顺序表一样,栈也有一个指针指向栈的栈底地址(顺序表首地址),有一个栈顶指针,记录栈顶的位置,还有一个记录容量大小的变量,我们在初始化时赋予初始空间4个。

数据结构初级<栈>_第4张图片 栈的初始化状态
// 初始化栈 
void StackInit(Stack* ps)
{
	assert(ps);//检查栈地址是否为空
	ps->_a = (STDataType*)malloc(sizeof(STDataType) * 4);//初始化申请四个空间
	if (!ps->_a)//检查空间是否申请成功
	{
		perror("malloc fail!\n");
		exit(-1);
	}
	ps->_capacity = 4;//空间计数为4个
	ps->_top = 0;//栈顶置为0
}

入栈函数

 我们可以想象入栈就像堆叠砖块一样,一层一层向上叠,在数组中就是元素个数不断增加,top下标(指针)不断后移(变大),每次插入时如果_top与_capacity相等则扩容,我们在写栈时不需要单独写扩容函数,因为涉及扩容的只要入栈函数。所以入栈函数就是在入栈前先检查容量是否已满,满了就扩容,然后直接将数据入栈到栈顶(_top位置),然后_top自加后移即可!

数据结构初级<栈>_第5张图片 入栈动图演示
// 入栈 
void StackPush(Stack* ps, STDataType data)
{
	assert(ps);//检查空指针

	if (ps->_top == ps->_capacity)//扩容
	{
		STDataType* tmp = (STDataType*)realloc(ps->_a, 2 * (ps->_capacity)  * sizeof(STDataType));//扩容原来的两倍

		ps->_a = tmp;//交付空间
		(ps->_capacity) *= 2;//空间翻两倍
	}

	ps->_a[(ps->_top)++] = data;//赋值栈顶-栈顶指针后移
}

出栈函数

对于元素出栈,我们只需要让栈顶指针_top自减即可,但需要检查栈是否为空,如果栈为空则终止操作。有人可能会疑惑不需要销毁被删除栈的数据吗?这里我们不需要担心,因为我们再次入栈时会覆盖该栈的数据。

数据结构初级<栈>_第6张图片 出栈动图演示

// 出栈 
void StackPop(Stack* ps)
{
	assert(ps);//检查空指针
	if (!StackEmpty(ps))//检查栈是否为空
	{
		--(ps->_top);//栈顶指针后移
	}
}

获取栈顶元素函数

获取栈顶元素时,由于_top指针每次入栈后自加,所以_top指针每次都指向下一个待插入位置,我们只需要将_top指针减一然后通过下标访问就能得到当前的栈顶元素。在获取栈顶元素前我们仍然需要检查栈是否为空,否则会出现越界情况!如果栈为空则返回-1(或其他提示性反馈)。

// 获取栈顶元素 
STDataType StackTop(Stack* ps)
{
	assert(ps);//检查空指针

	if(!StackEmpty(ps))//检查栈是否为空
		return ps->_a[(ps->_top)-1];

	return -1;//为空则返回-1(或其他提示性反馈)
}

获取栈元素个数函数

这个就非常简单了,我们只需要返回_top即可!

// 获取栈中有效元素个数 
int StackSize(Stack* ps)
{
    assert(ps);//检查空指针
	return (ps->_top);//返回_top
}

检查栈空函数

检查栈是否为空,只需要判断栈顶指针_top是否为0即可,如果为空返回1,如果不为空返回0 。

// 检测栈是否为空,如果为空返回1,如果不为空返回0 
int StackEmpty(Stack* ps)
{
	assert(ps);//检查空指针
	return (ps->_top == 0);
}

栈销毁函数

对于栈的销毁,我们只需要free是释放栈的空间地址指针_a,然后将空间和栈顶指针置0即可。

// 销毁栈 
void StackDestroy(Stack* ps)
{
	assert(ps);//检查空指针
	free(ps->_a);//释放栈空间
	ps->_a = NULL;//栈空间指针置空
	ps->_capacity = 0;空间变量置0
	ps->_top = 0;元素个数变量置0
}

总结

学完了栈的基础知识,我们可以发现,栈这种数据结构在实现其简单功能非常简单,但是栈的作用一般是辅助其他数据结构实现更复杂的功能的角色,所以掌握栈的基础操作也非常重要!

本次栈的知识分享就暂时先到这里啦,喜欢的读者可以多多点赞收藏和关注!

如果文章中有瑕疵,还请各位大佬细心点评和留言,我将立即修补错误,谢谢!

博客中的所有代码合集:顺序栈 

其他文章阅读推荐

数据结构初级<带头双向循环链表>_CSDN博客

数据结构初级<线性表之链表>_CSDN博客

数据结构初级<线性表之顺序表>_CSDN博客

欢迎读者多多浏览多多支持!

你可能感兴趣的:(数据结构(C语言),数据结构)