数据结构中的栈

2 篇文章 0 订阅
1 篇文章 0 订阅

在刚学习完C语言后,我设计了个程序实现10进制向n进制转换,我发现只能将其最终结果逆序输出。想正序输出一直没有实现。但是当我了解到了栈结构的时候豁然开朗。什么是栈结构?我的理解就是它就像是一个没盖子的瓶子,只能从一端进出。所以就有了先进去的后出来,后进去的先出来的说法。
栈 分为 顺序栈 和 链栈:
1. 顺序栈
和顺序表一样,这个线性结构实质上就是一段线型空间。只不过对这段线性空间进行了限制,而且多了些修饰这段空间的指针。

首先来看一个顺序栈应该包含哪些内容

typedef struct SeqStack
{
	int  top; //记录栈顶下标
	int* base;//指向栈底的指针
	int capacity;//当前已经分配的存储空间
}SeqStack;

顺序栈的初始化

void SeqStackInit(SeqStack* pst,int sz)//sz是你要申请空间的大小
{
	pst->capacity  = sz > SeqStack_Dafult_Size ? sz:SeqStack_Dafult_Size;
	pst->base = (int*)malloc(sizeof(SeqStack)*pst->capacity);
	pst->top = 0;
}

还有种初始化的方法就是可以减少一个参数

SeqStack* SeqStackCreate(int sz)//创建链表方法2
{
	SeqStack* pst = (SeqStack*)malloc(sizeof(SeqStack));//先让pst指向一个顺序栈
	pst->capacity = sz > SeqStack_Dafult_Size ? sz : SeqStack_Dafult_Size;
	pst->base = (int*)malloc(sizeof(pst->capacity)*pst->capacity);
	pst->top = 0;
	return pst;

这里面有个问题就是top初始值的问题,在人民邮电版本和清华大学的数据结构教材中top初始值均为-1,我们这里采取0;
区别:
在放入元素的时候初始值为0的情况先放入元素,后指针后移,
top初始值为-1的情况先指针后移,再放入元素。

出栈,原来的栈顶元素被删掉,由下一个顶替。 取栈顶元素,只是获取栈顶元素的值,不删除该元素
接下来我们来看栈中最常见的操作,取栈顶元素

int SeqStackTop(SeqStack* pst)
{
	if (SeqStackIsEmpty(pst))
	{
		printf("栈为空,无法取栈顶元素");
		return;
	}
	return pst->base[pst->top - 1];
}

下面再看插入元素

void SeqStackPush(SeqStack *pst, DataType x)
{
	if(SeqStackFull(pst))
	{
		printf("栈已满,%d 不能入栈.\n", x);
		return;
	}
	pst->base[pst->top++] = x;
}

删除元素

void SeqStackPop(SeqStack* pst)
{
	if (SeqStackIsEmpty(pst))
	printf("栈空间已空,不能继续删除");
	pst->top--;
}

展示

void SeqStackShow(SeqStack* pst)
{
	for (int i = pst->top - 1; i > 0; i--)
	{
		printf("%d  ", pst->base[i]);
	}
}

销毁

void SeqStackDestroy(SeqStack* pst)
{
	free(pst);
	free(pst->base);
}

需要强调的是销毁栈空间,不但要销毁这个空间,还要销毁指向这个空间的指针,这就是为什么看到2次free。
这样,一个完整的顺序栈就操作完成

接下来我们来看链栈
链栈 实际上就是链表加了些限定条件,但是少了很多限制(比如说链栈不存在栈满问题)反而比起链表还简单了一些,但是链栈也有很多难点,比如说怎么搭建框架。栈的数据结构操作起来相对链表来说比较简单,但是搭建栈实现栈的思想比较复杂(经常会用到二级指针),我们一起来看。

我们在创建链表的时候经常创建指向节点的指针,栈是要用到指向链表的指针,即指向节点指针的指针。也就是二级指针。

这里补充一个小知识点:指针

int a = 5;
int* p;
*p = &a;

通过简单的代码监视有无*的区别,
在这里插入图片描述

可以看到p是a的地址,而p有自己的地址,p的地址类型就会变成int**类型,但是* p的类型是int 类型。所以,到底加不加 (星号)取决于你要进行的操作,不要混为一谈。
再补充一点 运算符优先级
在这里插入图片描述
这几个运算符优先级别非常高,所以要进行操作时注意什么时候打括号,否则会出现很多问题。
首先来看栈的初始化

void ListStackInit(ListStack *pst)
{
	*pst = NULL;//初始化将栈赋空
}

我们来看链栈最复杂的部分 插入
插入的时候由于链栈的限制只能是头插

void ListStackPush(ListStack* pst, int x)
{
	StackNode* node = (StackNode*)malloc(sizeof(StackNode));
	assert(node);
	node->data = x;
	node->next = *pst;//结点连接栈
	*pst = node;
}

链栈删除栈顶

void ListStackPop(ListStack* pst)
{
	ListStack P = (*pst);//
	*pst = (*pst)->next;
	free(P);
}

链栈取栈顶元素

int ListStackTop(ListStack *pst)
{
	assert(*pst == NULL);
		return false;
		return(*pst)->data;
}

链栈展示函数

void ListStackShow(ListStack pst)
{
	StackNode* p = pst;
	while (p != NULL)
	{
		printf("%d ",p->data);
		p = p->next;
	}
}

以上就是数据结构中栈的基本操作。虽说结构不复杂,但是牵扯到二级指针问题,什么时候用一级指针什么时候用二级指针,所以还是有点苒,所以千万别混淆概念,否则你就要一步一步调试,超级痛苦的,写代码之前先理清楚思路。好了,今天就到这啦,觉得小编写的还不错的别忘了点赞哦!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值