一文读懂简单的数据结构——栈

专栏目录(数据结构与算法解析):https://blog.csdn.net/qq_40344524/article/details/107785323

栈是限定只能在表尾进行插入或删除操作的线性表,在学习栈的相关操作之前我们要先记住几个概念:栈底,栈顶,空栈,入栈(压栈),出栈


概念解释

栈底

线性表的尾部位置叫做栈底,它有一些特殊含义,后续在讲解代码时会讲到

栈顶

线性表的表头位置叫做栈顶,它是出栈和入栈的操作位置

空栈

当定义为栈的线性表中不存在任何元素的时候该线性表叫做空栈

入栈

也叫压栈,是指将元素放到栈中,此时栈顶指针要上移一位

出栈

将栈顶元素从栈中取出,栈顶指针下移一位

栈的具体操作过程见如下演示图
在这里插入图片描述

图:入栈出栈演示
从以上图例演示中我们可以看出栈的几个重要特性,首先栈最主要的特点是后进先出(越晚入栈的元素反而是越早出栈),其次栈也是具有线性特点的。

栈的实现

栈的实现有数组和链表两种方式,接下来我会通过代码对栈的实现和操作进行详细讲解:

数组栈

栈的创建
//数组栈是具有特定约束的数组,因此C语言中通常使用结构体进行表示
typedef int DataType;
typedef struct SeqStack
{
    DataType* data;
    int top;   	//栈顶
    int capacity;   //容量
    int bottom;	//栈底
}SeqStack;
//初始化栈
void SeqStackInit(SeqStack* stack)
{
	//1、申请可存放5个元素的内存空间
	stack->data = (DataType*)malloc(sizeof(DataType) * 5);
    //2、申请成功则进行初始化
	stack->top = 0;
	stack->bottom = 0;
	stack->capacity = 5;
}
入栈
void SeqStackPush(SeqStack* stack, DataType d)
{
    //1、判断栈是否满了,如果满了,就扩容,不满则直接压栈
    if(stack->top == stack->capacity)
    {
        //使用realloc调整容量大小为原先的二倍
        stack->data = (DataType*)realloc(stack->data, sizeof(DataType)*(stack->capacity)*2); 
        //扩容成功之后再调整容量大小
        stack->capacity *= 2;
    }
    //2、入栈
    stack->data[stack->top] = d;
    //3、移动栈顶位置
    stack->top++}
出栈
void SeqStackPop(SeqStack* stack)
{
    //1、判断是否为空栈,空栈不可进行出栈操作,判断栈空的方法有两种,1、判断栈顶是否在0位置,2、判断栈顶和栈底是否重合
    if(stack->top > 0)
    	//2、出栈,只需将栈顶向下移一位
    	pss->top--;
}
判断栈是否为空
bool SepStackIsNull(SeqStack* stack)
{
	//判断栈空的方法有两种,1、判断栈顶和栈底是否重合,2、判断栈顶是否在0位置
	if(stack->top == stack->bottom)
		return ture;
	return false;
}
取栈顶元素
//取栈顶元素
DataType SeqStackTop(SeqStack* stack)
{
	return stack->data[stack->top - 1];
}
销毁栈
//销毁栈
void SeqStackDestory(SeqStack* stack)
{
	if (stack->data)
	{
		free(stack->data);
		stack->data = NULL;
		stack->top = 0;
		stack->capacity = 0;
	}
}

链表栈

栈的创建
//链表栈是具有特定约束的链表,通常使用结构体表示结点和栈
typedef int DataType;
//结点定义
typedef struct Node
{
	DataType data;
	struct Node* next;
}Node;
//链式栈定义
typedef struct LinkStack
{
	Node* top;   	//栈顶指针
	int nCount; //个数
}LinkStack;
//初始化链式栈
void LinkStackInit(LinkStack* lstack)
{
	lstack->nCount = 0;
	lstack->top = NULL;
}
入栈
void LinkStackPush(LinkStack* lstack, DataType d)
{
 	Node* node = (Node*)malloc(sizeof(Node));
	node->data = d;
	node->next = NULL;
    //入栈
	node->next = lstack->top;
	lstack->top = node;
	lstack->nCount++;
}
出栈
void LinkStackPop(LinkStack* lstack)
{
	Node* del = NULL;
    //判断栈是否为空
	if (lstack->nCount == 0)
	{
		return;
	}
 
    //2、出栈
	del = lstack->top;
	lstack->top = del->next;
	lstack->nCount--;
	free(del);
	del = NULL;
}
判断栈是否为空
//判断栈是否为空
bool LinkStackEmpty(LinkStack* lstack)
{
	if(lstack->nCount == 0)
		return true;
	return false;
}
取栈顶元素
//获取栈顶元素
DataType LinkStackTop(LinkStack* lstack)
{
	return lstack->top->data;
}
销毁栈
//销毁栈
void LinkStackDestory(LinkStack* lstack)
{
	Node* del = NULL;
	
	while (lstack->top)
	{
		del = lstack->_top;
		lstack->top = del->next;
		free(del);
		del = NULL;
		pls->nCount--;
	}
}

总结

通过上述讲解想来大家也看出来了栈的核心特点就是后进先出,基于这个特点我们会在很多场景用到栈的结构,包括内容的逆序输出,检查成对符号使用规范,数制转换等,通常我们在开发中无需自己定义栈,学习上述代码主要是为了更好了解栈的特点和使用方式。


栈的讨论就到这里,下一节详解另一个特殊的线性数据结构——队列,它与栈有区别也有一定的联系。


以上是我的一些粗浅的见解,有表述不当的地方欢迎指正,谢谢!


表述能力有限,部分内容讲解的不到位,有需要可评论或私信,看到必回…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

书山客

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

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

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

打赏作者

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

抵扣说明:

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

余额充值