手撕数据结构 —— 栈(C语言讲解)

news/2024/10/16 18:13:55 标签: 数据结构

目录

1.认识栈

什么是栈

栈的示意图

2.如何实现栈

3.栈的实现

Stack.h中接口总览

具体实现

结构的定义

初始化栈

销毁栈

入栈

出栈

取栈顶元素

获取有效元素的个数

判断栈是否为空

4.完整代码附录

Stack.h

Stack.c


1.认识栈

什么是栈

栈是一种特殊的线性表,只允许在固定的一端进行数据的插入和删除操作;

  • 进行数据的插入和删除的一端叫做栈顶,另一端叫做栈底。
  • 栈中的数据必须严格遵守后进先出的原则,这也是栈这种数据结构最重要的特点。

栈的示意图

两个专业术语:

  • 入栈:栈的插入数据元素的操作叫做入栈。

  • 出栈:栈的删除数据元素的操作叫做出栈。

入栈和出栈都是在栈顶进行的。

2.如何实现栈

要想实现栈,必须满足以下两个条件:

  • a、控制在一端进行数据的插入和删除
  • b、满足后进先出的原则。

基于上述条件,我们可以使用数组或者链表来实现栈,那么使用哪种数据结构来实现栈更好呢?

我们可以对比一下:

数组(顺序表)链表(单链表)
头插效率O(N)O(1)
头删效率O(N)O(1)
尾插效率O(1)O(N)
尾删效率O(1)O(N)

可以看出,使用数组(顺序表)来实现栈的话,需要将尾部作为栈顶,插入数据和删除数据的时间复杂度都是O(1)。使用链表(单链表)来实现栈的话,需要将头部作为栈顶,插入数据和删除数据的时间复杂度都是O(1)。

但是相对而言,使用数组实现栈更优,因为数组没有太多的指针操作,删除数据的时候只需要让size-- 即可(size是数组中有效元素的个数),插入数据的时候直接赋值即可。

我们实现栈的时候,采用数组的形式实现数组栈。

3.栈的实现

实现栈的时候,我们主要实现Stack.h 和 Stack.c这两个文件,Stack.h用来存放声明,Stack.c用来存放定义。

Stack.h中接口总览

具体实现

结构的定义

因为静态的栈不实用,我们实现的数组栈采用动态增长的形式。

  • a指向动态开辟的内存空间的起始地址。
  • top指向栈顶元素的下一个位置。
  • capacity表示栈的容量,当容量不够的时候,需要动态扩容。

初始化栈

初始化栈的之后,将a置为空,capacity和top都为0。

  • top初始化为0表示top指向栈顶元素的下一个位置。
  • top如果初始化为-1表示top指向栈顶元素。
  • 两种方式实现都可以,我们采用第一种,这样的好处是top的值直接就可以表示栈中数据元素的个数。

注意:指向物理空间的指针ps不能为空,后面涉及该指针变量的地方都一样。

销毁栈

销毁栈的时候,只需要将动态申请的空间释放,并将指向这块空间的指针置空;然后将top和capacity都置为0即可。

入栈

实现入栈需要注意以下几个点:

  • 栈空间不能为空,使用断言assert()暴力判断。
  • 注意空间是否足够,空间不够时需要扩容。
  • 元素入栈之后,top记得++。

出栈

出栈时需要注意以下几点:

  • 指向物理空间的指针不能为空。
  • 栈中元素个数 >0 时元素才能出栈。
  • 元素出栈之后记得将top-- 。 

取栈顶元素

我们定义结构的时候,将top定义为栈顶元素的下一个位置,top-1就表示栈顶元素的下标,直接返回栈顶元素即可。

获取有效元素的个数

top也能表示栈中有效元素的个数,直接返回top即可。

判断栈是否为空

top表示栈中有效数据的个数,当top == 0时,栈为空;当top != 0时,栈不为空。

4.完整代码附录

Stack.h

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef int STDataType;
typedef struct Stack
{
	STDataType* a;    // 指向动态开辟的顺序表 
	int top;          // 指向栈顶元素的下一个位置 
	int capacity;     // 表示栈的容量 
}ST;

void STInit(ST* ps);                 // 初始化栈 
void STDestroy(ST* ps);              // 销毁栈 
void STPush(ST* ps, STDataType x);   // 入栈 
void STPop(ST* ps);                  // 出栈 
STDataType STTop(ST* ps);            // 取栈顶元素 
int STSize(ST* ps);                  // 获取有效元素的个数 
bool STEmpty(ST* ps);                // 判断栈是否为空 

Stack.c

#include "Stack.h"

void STInit(ST* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}

void STDestroy(ST* ps)
{
	assert(ps);

	free(ps->a);
	ps->a = NULL;
	ps->top = ps->capacity = 0;
}

void STPush(ST* ps, STDataType x)
{
	assert(ps);

	if (ps->top == ps->capacity)     // 当 top==capacity时就需要扩容了  
	{
		// 初始空间为4,扩容按照两倍扩 
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		
		// 当a为空的时候,realloc的功能类似于malloc 
		STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newCapacity);
		
		if (tmp == NULL)             // 判断扩容是否成功 
		{
			perror("realloc fail");
			exit(-1);
		}

		ps->a = tmp;                 // 将开辟的空间赋值给变量a 
		ps->capacity = newCapacity;  // 更新容量 
	}

	ps->a[ps->top] = x;              // 元素入栈 
	ps->top++;                       // top++指向栈顶元素的下一个位置 
}


void STPop(ST* ps)
{
	assert(ps);          // 指针不能为空 

	assert(ps->top > 0); // 栈中元素个数 >0 元素才能出栈 

	--ps->top;           // 元素出栈之后记得将top-- 
}

STDataType STTop(ST* ps)
{
	assert(ps);            
 
	assert(ps->top > 0);        // 栈中有元素 

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

int STSize(ST* ps)
{
	assert(ps);

	return ps->top;
}

bool STEmpty(ST* ps)
{
	assert(ps);

	return ps->top == 0;
}

http://www.niftyadmin.cn/n/5708321.html

相关文章

利用vmware在移动硬盘安装Ubuntu2go

安装 买个移动硬盘&#xff0c;usb插电脑&#xff0c;磁盘管理看磁盘序列号 vmware新建虚拟机 这一步选择磁盘管理里面看到的磁盘4 先不要开机&#xff0c;选择设置里面UEFI 和安装正常Ubuntu一致操作即可&#xff0c;这里可以不选高级&#xff0c;默认一个引导分区&…

Python 实现电话号码和Email地址提取程序

Python 实现电话号码和Email地址提取程序 背景 在日常工作或学习中&#xff0c;我们经常需要从网页或文档中提取信息&#xff0c;比如电话号码和E-mail地址。手动查找和提取这些信息可能会耗费大量时间&#xff0c;而自动化工具可以帮助我们快速完成这个任务。 本篇博客将带…

前端开发攻略---8种方法实现在浏览器中跨页面通信

目录 1、BroadCast Channel 2、Service Worker 3、LocalStorage 4、Shared Worker 5、IndexedDB 6、Cookie 7、Window 8、Websocket 总结&#xff1a; 1、BroadCast Channel 1、创建文件sender.html <!DOCTYPE html> <html lang"zh"><head&g…

idea如何拉取git仓库新的项目,有git仓库地址

在 IntelliJ IDEA 中拉取一个新的 Git 仓库项目&#xff0c;你可以按照以下步骤操作&#xff1a; 打开 IntelliJ IDEA。 如果你还没有打开任何项目&#xff08;即处于欢迎界面&#xff09;&#xff0c;请选择“Get from VCS”&#xff08;从版本控制系统获取&#xff09;。如果…

最经典无人机数据集

在现代科技的浪潮中&#xff0c;无人机技术就像一颗闪亮的星星&#xff0c;吸引了全球的目光。它们不仅在物流、农业、环境监测和灾害救援等领域大显身手&#xff0c;还为商业世界带来了无限可能。然而&#xff0c;随着无人机的数量不断增加&#xff0c;如何有效地管理和利用这…

MySQL 密码忘记了怎么办?

在使用 MySQL 的过程中&#xff0c;有时候我们可能会忘记密码。别担心&#xff0c;本文将详细介绍在 Windows 系统下如何重新设置 MySQL 密码。 一、停止 MySQL 服务 打开“服务”窗口&#xff0c;可以通过在 Windows 搜索栏中输入“服务”来找到并打开它。在服务列表中找到“…

OpenStack服务Swift重启失效(已解决)

案例分析Swift重启失效 1. 报错详情 在重新启动 VMware 虚拟机后&#xff0c;我们发现 OpenStack 的 Swift 服务出现了 503 Service Unavailable 错误。经过排查&#xff0c;问题根源在于 Swift 服务所使用的存储挂载是临时挂载&#xff0c;而非永久挂载。 Swift 服务依赖于…

Visual Studio 2022 配置 Boost 库

一、使用预编译版本 尽量不要使用预编译版本&#xff0c;因为可能构建的不完全&#xff0c;还得重新构建&#xff0c;不如一步到位 1. 下载预编译的 Boost 库 下载&#xff1a;Boost C Libraries - Browse /boost-binaries at SourceForge.net 2. 选择 msvc 版本&#xff0…