数据结构与算法—栈

news2024/9/22 15:40:05

目录

一、栈的概念及结构

二、栈的实现 

1、声明栈结构体

2、初始化

3、 销毁

4、 入栈(压栈)

5、出栈(弹栈)

6、栈的大小

 OJ练习

 完整版:

Stack.h声明

Stack.c函数

test.c参考测试用例


一、栈的概念及结构

栈(Stack)是一种常见的数据结构,它遵循一种特定的数据存储和访问方式,通常用于管理数据的后进先出(Last-In-First-Out,LIFO)的操作顺序。这意味着最后压入栈的元素将首先被弹出,类似于一叠盘子,你总是在最上面放入和拿出盘子。

栈通常支持以下两种基本操作:

  1. 压栈(Push):将元素添加到栈的顶部。这个操作通常叫做“入栈”。
  2. 弹栈(Pop):从栈的顶部移除元素。这个操作通常叫做“出栈”。

 

二、栈的实现 

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小,(CPU高速缓存命中率会更高)

1、声明栈结构体

typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;
  • 将栈的数据类型设置别名STDataType,方便后续修改。
  • 定义结构体名称的别名为ST。
  •  结构体成员*a用于指向存储栈元素的动态数组。
  • top为栈顶的位置。
  • capacity为当前栈的容量。

2、初始化

void STInit(ST* pst)
{
	assert(pst);
	pst->a = NULL;
	pst->top = 0;
	pst->capacity = 0;
}
  • assert判断栈的地址是否为空,为空则报错。
  • 将指针a初始化为空,栈顶位置top初始化为0,容量capacity初始化为0。

3、 销毁

void STDestroy(ST* pst)
{
	assert(pst);
	free(pst->a);
	pst->a = NULL;
	pst->top = 0;
	pst->capacity = 0;
}
  •  assert判断栈的地址是否为空,为空则报错。
  • free释放结构体成员a的空间,以避免内存泄漏,然后将a置空。
  • 将栈顶位置top赋值为0,表示栈已空。
  • 将容量capacity赋值为0,表示容量为0.

4、 入栈(压栈)

void STPush(ST* pst,STDataType x)
{
	if (pst->top == pst->capacity) {
		int newCapacity = pst->capacity == 0 ? 4 :pst-> capacity * 2;
		STDataType* tmp = (STDataType*)realloc(pst->a, newCapacity * sizeof(STDataType));
		if (tmp == NULL) {
			perror("realloc fail");
			return;
		}
		pst->a = tmp;
		pst->capacity = newCapacity;
	}
	pst->a[pst->top] = x;
	pst->top++;
}
  • 每次数据入栈都先检查栈的容量,top与capacity相等分为两种情况:第一次入栈或栈已满
  1. 第一次入栈时,新栈newCapacity的容量为4,然后为其开辟相应大小的空间,
  2. 如果已满即top与capacity相等,则新栈newCapacity的大小为当前的两倍,然后对当前空间进行扩容。
  • 用中间变量接收扩容的空间,防止扩容失败丢失数据。
  •  如果扩容失败则调用perror打印错误信息。
  • 将中间变量赋值给 a。
  • 更新容量为newCapacity的值。
  • 将接收的参数 x 入栈到top位置,然后更新top位置向上移动一位。

5、出栈(弹栈)

出栈需要三个函数,STPop 用于弹出元素,STTop 用于获取栈顶元素的值,而 STEmpty 用于检查栈是否为空。

void STPop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));
	pst->top--;
}

STDataType STTop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));
	return pst->a[pst->top - 1];
}

bool STEmpty(ST* pst)
{
	assert(pst);
	return pst->top == 0;
}

void STPop(ST* pst) 函数:

  • 这个函数用于弹出栈顶元素,也就是将栈顶位置 pst->top 的值减一,相当于将栈顶元素从栈中移除。
  • assert(pst) 确保传入的 pst 指针不为空。
  • assert(!STEmpty(pst)) 确保栈不为空,因为如果栈已经为空,就不应该执行弹出操作,否则会导致错误。
  • pst->top--; 将栈顶位置减一,以实现弹出操作。

STDataType STTop(ST* pst) 函数:

  • 这个函数用于获取栈顶元素的值,但不将其从栈中移除。
  • assert(pst) 确保传入的 pst 指针不为空。
  • assert(!STEmpty(pst)) 确保栈不为空,因为如果栈为空,就不能安全地访问栈顶元素。
  • return pst->a[pst->top - 1]; 返回栈顶位置 pst->top 上的元素值,由于栈是从0开始索引的,所以需要减一。

bool STEmpty(ST* pst) 函数:

  • 这个函数用于检查栈是否为空。
  • assert(pst) 确保传入的 pst 指针不为空。
  • return pst->top == 0; 返回一个布尔值,表示栈是否为空。如果栈顶位置 pst->top 等于0,说明栈为空,返回 true;否则返回 false

6、栈的大小

int STSize(ST* pst)
{
	assert(pst);
	return pst->top;
}
  •   assert判断栈的地址是否为空,为空则报错。
  • 返回栈的大小,即栈顶位置 pst->top 的值。栈顶位置表示栈中元素的数量,因为栈是从0开始索引的,所以 pst->top 的值等于栈中元素的数量。

 OJ练习

20. 有效的括号

 

由于我们用C语言做这道题,所以代码前要加上咱们实现的栈的代码,同时要将数据类型STDataType改为char类型。

typedef char STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;

void STInit(ST* pst);
void STDestroy(ST* pst);
void STPush(ST* pst, STDataType x);
void STPop(ST* pst);
STDataType STTop(ST* pst);
bool STEmpty(ST* pst);
int STSize(ST* pst);

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

void STDestroy(ST* pst)
{
	assert(pst);
	free(pst->a);
	pst->a = NULL;
	pst->top = 0;
	pst->capacity = 0;
}

void STPush(ST* pst,STDataType x)
{
	if (pst->top == pst->capacity) {
		int newCapacity = pst->capacity == 0 ? 4 :pst-> capacity * 2;
		STDataType* tmp = (STDataType*)realloc(pst->a, newCapacity * sizeof(STDataType));
		if (tmp == NULL) {
			perror("realloc fail");
			return;
		}
		pst->a = tmp;
		pst->capacity = newCapacity;
	}
	pst->a[pst->top] = x;
	pst->top++;
}

void STPop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));
	pst->top--;
}

STDataType STTop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));
	return pst->a[pst->top - 1];
}

bool STEmpty(ST* pst)
{
	assert(pst);
	return pst->top == 0;
}

int STSize(ST* pst)
{
	assert(pst);
	return pst->top;
}

bool isValid(char* s) {
    ST st;
    STInit(&st);
    while (*s) {
        if (*s == '(' || *s == '[' || *s == '{') {
            STPush(&st, *s);
        }
        else {
            if (STEmpty(&st)) {
                STDestroy(&st);
                return false;
            }
            char top = STTop(&st);
            STPop(&st);
            if ((top != '(' && *s == ')') ||
                (top != '{' && *s == '}') ||
                (top != '[' && *s == ']')) {
                STDestroy(&st);
                return false;
            }
        }
        s++;
    }
    bool ret = STEmpty(&st);
    STDestroy(&st);
    return ret;
}
  • 创建栈结构体ST变量 st,然后进行初始化。
  • 以*s为循环进行条件
  • 首先,创建一个名为 st 的 ST 结构体实例,并使用 STInit 初始化它。

  • 然后,遍历输入字符串 s 中的每个字符。
  • 对于每个字符,如果是左括号 '(','[','{' ,则将其推入栈中。
  • 如果是右括号 ')',']','}' ,则执行以下操作:

检查栈是否为空,如果为空,表示没有对应的左括号,则销毁栈,返回 false

否则,弹出栈顶元素,将其与当前右括号进行匹配。如果不匹配,则销毁栈,返回 false

  • 最后,遍历完整个字符串后,检查栈是否为空。如果栈为空,表示所有括号都成功匹配,返回 true,否则返回 false
  • 最后,调用 STDestroy 销毁栈,并返回最终的匹配结果。

 完整版:

Stack.h声明

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;

void STInit(ST* pst);
void STDestroy(ST* pst);
void STPush(ST* pst, STDataType x);
void STPop(ST* pst);
STDataType STTop(ST* pst);
bool STEmpty(ST* pst);
int STSize(ST* pst);

Stack.c函数

#include "Stack.h"

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

void STDestroy(ST* pst)
{
	assert(pst);
	free(pst->a);
	pst->a = NULL;
	pst->top = 0;
	pst->capacity = 0;
}

void STPush(ST* pst,STDataType x)
{
	if (pst->top == pst->capacity) {
		int newCapacity = pst->capacity == 0 ? 4 :pst-> capacity * 2;
		STDataType* tmp = (STDataType*)realloc(pst->a, newCapacity * sizeof(STDataType));
		if (tmp == NULL) {
			perror("realloc fail");
			return;
		}
		pst->a = tmp;
		pst->capacity = newCapacity;
	}
	pst->a[pst->top] = x;
	pst->top++;
}

void STPop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));
	pst->top--;
}

STDataType STTop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));
	return pst->a[pst->top - 1];
}

bool STEmpty(ST* pst)
{
	assert(pst);
	return pst->top == 0;
}

int STSize(ST* pst)
{
	assert(pst);
	return pst->top;
}

test.c参考测试用例

#include "Stack.h"

void test1()
{
	ST st;
	STInit(&st);
	STPush(&st, 999);
	STPush(&st, 99);
	STPush(&st, 9);
	//printf("%d ", STTop(&st));
	//STPop(&st);
	//printf("%d ", STTop(&st));

	while (!STEmpty(&st)) {
	    printf("%d ", STTop(&st));
	    STPop(&st);
    }
	STDestroy(&st);
}

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1134993.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CLIP系列:CLIP:沟通文本和图像的桥梁

CLIP沟通文本和图像的桥梁。 SOTA的视觉任务模型需要固定的监督数据对&#xff0c;比如-大象&#xff0c;-兔子。这种方式在特定数据集上能够拥有很好的性能&#xff0c;但是在其他未知类别上的性能就会急剧下降。这种监督形式限制了模型的通用性&#xff0c;因为需要额外的数据…

linux配置静态路由

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言硬件&操作系统一、静态路由是什么&#xff1f;二、开始配置1.netplan2.NetworkManager1.CLI2.Desktop 三、开始测试总结 前言 最近有一个需求&#xff0c;…

C++数据结构X篇_23_快速排序(最快、不稳定的排序)

文章参考十大经典排序算法-快速排序算法详解进行整理补充。快速排序是最快的排序方法。 排序思路&#xff1a;分治法-挖坑填数&#xff1a;大问题分解为各个小问题&#xff0c;对小问题求解&#xff0c;使得大问题得以解决 文章目录 1. 什么是快速排序1.1 概念1.2 算法原理1.3 …

淘宝商品链接获取淘宝商品评论数据(用 Python实现淘宝商品评论信息抓取)

在网页抓取方面&#xff0c;可以使用 Python、Java 等编程语言编写程序&#xff0c;通过模拟 HTTP 请求&#xff0c;获取淘宝多网站上的商品详情页面评论内容。在数据提取方面&#xff0c;可以使用正则表达式、XPath 等方式从 HTML 代码中提取出有用的信息。值得注意的是&#…

android10.0(Q)编译安卓内核(pixel 2)

下载内核源码 1.查看内核版本 首先需要看一下内核的版本&#xff0c;可以在手机中看到内核版本 2.下载该内核版本对应的源码 cd ~/mount/project/androidq git clone https://aosp.tuna.tsinghua.edu.cn/android/kernel/msm.git cd msm git checkout 4fecde07e68d执行结果如…

Python之作业(三)

Python之作业&#xff08;三&#xff09; 练习题 给出3个整数&#xff0c;使用if语句判断大小&#xff0c;并升序输出有一个列表lst [1,4,9,16,2,5,10,15],生成一个新列表&#xff0c;要求新列表元素是lst相邻2项的和随机生成100个产品ID&#xff0c;ID格式如下 顺序的数字6…

SD-WAN跨境网络专线|跨境访问无忧!让海外SaaS平台与视频会议更稳定轻松的解决方案

在现如今全球化的时代&#xff0c;企业都有布局全球或是有潜力的国家&#xff0c;在海外开分公司必不可少&#xff0c;那与海外合作伙伴进行沟通与合作已经成为企业的常态。但是&#xff0c;访问海外的SaaS平台和进行视频会议时&#xff0c;我们经常会遇到网络不稳定、速度慢的…

m1 安装 cocoapods

其实最终解决问题很简单&#xff0c;麻烦的是如果找到解决问题的答案。 网上的答案一大堆&#xff0c;但不一定适合你的电脑&#xff0c;就好像天下的女人到处有&#xff0c;但不一定都适合你&#xff0c;一定要亲自试验一下才知道结果。 前提条件&#xff1a; 命令行工具&am…

Dunham‘s sports EDI需求分析

Dunhams Sports&#xff0c;成立于1937年&#xff0c;是美国领先的运动用品零售商之一。公司总部位于密歇根州&#xff0c;致力于提供广泛的体育用品和户外装备。Dunhams Sports的使命是为顾客提供最优质的运动体验&#xff0c;他们以卓越的服务和品质&#xff0c;赢得了无数荣…

【访问控制】—>《熟练使用ACL进行上网行为管理》

✍ 标准和高级ACL功能介绍&#xff1b; ✍ 思科和华为ACL功能有什么区别&#xff1f; ✍ 现网中ACL都有哪些使用场景&#xff1f; -- ACL - 访问控制列表 - 控制&#xff1a; 能通/不能通 -- ACL - 结合功能 list - 简化版本的行为管理 -- 插件性质的功能 --…

echarts 仪表盘统计图

<!--仪表盘统计图--><div class"ybptx" ref"btryzb"></div>mounted(){this.getBtData();}getBtData() {let chart this.$echarts.init(this.$refs.btryzb);let data_czzf this.cznlzhpj.czzfs;let option {series: [{name: 内层数据刻…

水表能实时监测哪些参数?

你是否曾经想过&#xff0c;你家的水表是如何工作的?它不仅能够记录你的用水量&#xff0c;还能实时监测一些重要的参数&#xff0c;比如水压、水温、水质等。这些参数对于保证用水安全和节约用水资源都有着重要的作用。接下来&#xff0c;小编就来为大家详细的介绍下水表能实…

java中的数据源

为什么要使用数据源 jdbc是什么 JDBC 就是使用Java语言操作关系型数据库的一套API&#xff0c;我们开发的同一套Java代码是无法操作不同的关系型数据库&#xff0c;因为每一个关系型数据库的底层实现细节都不一样。如果这样&#xff0c;问题就很大了&#xff0c;在公司中可以在…

虚拟机Ubuntu - 环境配置

文章目录 安装虚拟机安装必要工具修改IP地址修改主机名安装Java方法一&#xff1a;apt 安装方法二&#xff1a;使用PPA仓库&#xff08;适用于Ubuntu 18.04以上版本&#xff09; 远程连接另一台宿主机的虚拟机方法一&#xff1a;NAT连接方法二&#xff1a;桥连接&#xff08;推…

selenium判断元素可点击、可见、可选

1、判断元素是否可以点击 判断元素是否可以点击&#xff0c;WebElement对象调用is_enabled() is_enabled()方法返回一个布尔值&#xff0c;若可点击返回&#xff1a;True。若不可点击则返回&#xff1a;False from selenium import webdriver import time from selenium.web…

LeetCode 热题 100 - 第1题:两数之和

LeetCode 热题 100 - 第1题:两数之和 原题题目理解普通的解题思路---遍历查找进阶的解题思路---哈希查找 原题 给定一个整数数组 nums和一个整数目标值target&#xff0c;请你在该数组中找出 和为目标值 target的那两个整数&#xff0c;并返回它们的数组下标。 你可以假设每种…

Docker 镜像常用命令总结

目录 1. Docker镜像相关命令(重点掌握) 1.1 docker pull 镜像名称 [:tag] 拉取镜像 1.2 docker search 镜向名称 (查询某个镜像) 1.3 docker images 列出当前主机上所有镜像 1.4 docker rmi 镜像ID 删除镜像 1.5 docker system df 查看所有镜像容器所占空间 2. Docker …

每日一练——快速合并2个有序数组

每日一练来喽~~~ 今天up主为大家分享一个&#xff0c;快速合并2个有序数组的法子&#xff0c;注意听哟&#xff01; 题目&#xff1a; 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0c;分别表示 nums1 和 nums2 中的元素数…

2、TB6600驱动器介绍【51单片机控制步进电机-TB6600系列】

摘要&#xff1a;本节介绍TB6600驱动器界面及关键参数设置 一、驱动器功能界面 二、关键参数 输入电压&#xff1a;DC9-42V 输出电流&#xff1a;0.5-4A 最大功耗&#xff1a;160W 细分设置&#xff1a;1,2/A,2/B,4,8,16,32 工作温度&#xff1a;-10~45C 信号口驱动电流&…

用ST-LINK 出现连接失败【已解决】

出现的问题&#xff1a;not connect to target! 13:33:39 : Can not connect to target! Please select "Connect Under Reset" mode from Target->Settings menu and try again. If youre trying to connect to a low frequ…