数据结构漫游记:动态实现栈(stack)

嘿,各位技术潮人!好久不见甚是想念。生活就像一场奇妙冒险,而编程就是那把超酷的万能钥匙。此刻,阳光洒在键盘上,灵感在指尖跳跃,让我们抛开一切束缚,给平淡日子加点料,注入满满的passion。准备好和我一起冲进代码的奇幻宇宙了吗?Let's go!

我的博客:yuanManGan

我的专栏:C++入门小馆 C言雅韵集 数据结构漫游记 闲言碎语小记坊 题山采玉

目录

一.栈的认识

二.存储栈的结构选取:

数组:

链表

三栈的模拟实现

结构定义:

初始化:

入栈:

销毁栈:

判空:

出栈:

获取栈顶元素

获取栈中有效元素个数

测试:


相信大家对于栈那一块还是比较了解,在学校c语言时,一定了解过函数栈帧之类的东西,我们就来用c语言来实现一下这个数据结构

一.栈的认识

栈(stack)作为一种数据结构,它遵循一个准则就是后进先出(或者是先进后出),就像一个箱子里先放了的东西要最后才能拿出来

我们只能在一边进行操作,关于栈有一些名词

栈顶:最后入栈的那个元素 栈底:第一个入栈的元素

入栈(压栈):向栈顶加入元素 出栈:删除栈顶元素

空栈:栈里面没有元素

二.存储栈的结构选取:

我们之前学习过数组和链表作为基础来实现数据结构,那我们的栈能不能用其中一种来实现呢,

数组:

我们如果用数组来模拟栈,栈底指向最后一个元素,然后如果是出栈操作,只需要将数组个数减减,将最后一个元素弄成了无效元素即可,入栈也很简单a++size = x 即可,时间复杂度都是O(1),这就是我们理想的结构,我们有同学就会发现,这玩意不就是顺序表吗,对这就是顺序表,入栈出栈操作,就是顺序表中的尾插头插操作,栈就是访问受限的顺序表。

链表

有了上面的理解,我们就知道实现栈就是要有一个容易实现尾插尾删的结构,但是我们的链表实现尾插尾删的时间复杂度都是O(n)啊,有没有办法能降低O(1)呢。我们知道链表实现头插头删的操作时间复杂度满足我的的预期,咦那我们能不能将栈顶放在头结点,入栈时我们头插,出栈时头删。

但我们为什么不选择链表而更好选择数组来实现栈呢?我们都知道我们的链表有个致命的缺点,就是容易造成空间浪费,空间利用率不高。

三栈的模拟实现

结构定义:

cpp 复制代码
// 支持动态增长的栈
typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;		// 栈顶
	int capacity;  // 容量 
}Stack;

这里的top指向的是将要插入的位置。

初始化:

cpp 复制代码
// 初始化栈 
void StackInit(Stack* ps)
{
	ps->a = NULL;
	ps->capacity = ps->top = 0;
}

入栈:

cpp 复制代码
// 入栈 
void StackPush(Stack* ps, STDataType data)
{
	assert(ps);
	if (ps->top == ps->capacity)
	{//扩容
		int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		STDataType* tmp = (STDataType*)realloc(ps->a, newcapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("扩容失败\n");
			exit(1);
		}
		ps->a = tmp;
		ps->capacity = newcapacity;
	}
	ps->a[ps->top++] = data;
}

这里的申请结点,并没有像顺序表一样单独分装一个函数,因为我们只有这一个地方会增加结点。

销毁栈:

cpp 复制代码
// 销毁栈 
void StackDestroy(Stack* ps)
{
	if (ps->a)
	{
		free(ps->a);
		ps->a = NULL;
	}
	ps->capacity = ps->top = 0;
}

判空:

cpp 复制代码
bool StackEmpty(Stack* ps)
{ 
	assert(ps);
	return ps->top == 0;
}

出栈:

cpp 复制代码
// 出栈 
void StackPop(Stack* ps)
{
	assert(!StackEmpty(ps));
	ps->top--;
}

获取栈顶元素

cpp 复制代码
// 获取栈顶元素 
STDataType StackTop(Stack* ps)
{
	assert(!StackEmpty(ps));
	return ps->a[ps->top - 1];
}

获取栈中有效元素个数

cpp 复制代码
int StackSize(Stack* ps)
{
    assert(ps);
    return ps->top;
}

这些功能都很简单就实现了。

测试:

cpp 复制代码
void test()
{
	Stack st;
	StackInit(&st);
	for (int i = 0; i < 10; i++)
	{
		StackPush(&st, i);

	}
	while (!StackEmpty(&st)) //StackSize(&st)
	{
		STDataType top = StackTop(&st);
		printf("%d\n", top);
		StackPop(&st);
	}
	StackDestroy(&st);
}

int main()
{
	test();
	return 0;
}

结果:

完结撒花!

相关推荐
CSharp精选营4 天前
关系型 vs 非关系型:从原理到选型,一文搞定数据库核心分类
数据结构·nosql·关系型数据库·非关系型数据库·技术选型
刘马想放假7 天前
Modbus 全栈技术解析:TCP、RTU、ASCII、RTU over TCP
数据结构·网络协议
北域码匠8 天前
冒泡排序太慢?鸡尾酒排序双向优化,原生 C# 零第三方库完整代码
数据结构·排序算法·泛型·c# 算法·鸡尾酒排序·原生 c# 开发·冒泡排序优化·嵌入式算法
Darling噜啦啦15 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
小小工匠16 天前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
玖玥拾16 天前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
Qres82116 天前
算法复键——树状数组
数据结构·算法
牛油果子哥q16 天前
并查集(DSU)超精讲,路径压缩、按秩合并、万能模板、连通性判定、最小生成树与刷题实战全解
数据结构·c++·最小生成树·并查集
凌波粒16 天前
LeetCode--491.递增子序列(回溯算法)
数据结构·算法·leetcode
WL学习笔记16 天前
单项不带头不循环链表
数据结构·链表