【数据结构】详解栈

今天我们主要来了解栈!如果对知识点有模糊,可翻阅以往文章哦!

个人主页:小八哥向前冲~-CSDN博客

所属专栏:数据结构【c语言版】_小八哥向前冲~的博客-CSDN博客

c语言专栏:c语言_小八哥向前冲~的博客-CSDN博客

值得注意的是,如果你十分了解顺序表和链表,今天这期会很轻松哦!

哈哈哈哈!当然,这期也能检测你对顺序表和链表的理解!一起看看吧!

目录

栈的定义

顺序表和链表的比较

栈的实现--顺序表

初始化

栈为空的判定

入栈

出栈

销毁

栈顶数据

数据个数

题目操练:配括号问题

栈的实现--链表

栈为空的判定

入栈

出栈

销毁

栈顶数据

数据个数

码源--栈(顺序表)

码源--栈(链表)


栈的定义

  • :一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端 称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
  • 压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶
  • 出栈:栈的删除操作叫做出栈。出数据也在栈顶

上图理解一下:

注意:遵循后进先出的原则!

知道了这个原则,我们来巩固一下:

1.一个栈的初始状态为空。现将元素1、2、3、4、5、A、B、C、D、E依次入栈,然后再依次出栈,则元素出 栈的顺序是( )。

A .12345ABCDE

B.EDCBA54321

C.ABCDE12345

D.54321EDCBA

2.若进栈序列为 1,2,3,4 ,进栈过程中可以出栈,则下列不可能的一个出栈序列是()

A.1,4,3,2

B.2,3,4,1

C.3,1,4,2

D.3,4,2,1

显然:1.B      2.C

相信第一题不难,我们解释一下第二题:看到C选项,1,2,3进栈后,3出栈,而第二次出栈的只能是2或4,不可能是1,所以C错误!

了解了栈的概念,我们实现这个栈是使用顺序表还是链表呢?

  • 如果是顺序表的话,我们的栈顶应该要在数组末尾!如果在数组头部的话,数据进栈时还需要挪动其余数据以便数据的存入!效率很低
  • 如果是链表的话,我们的栈顶要在链表的头入栈时,头插即可!如果栈顶在链表尾部的话,虽然入栈尾插即可,但需要遍历,效率低,那么这时就需要使用双链表!

综上所述,我们栈使用顺序表较好!(两种都实现看看)

上图看看它们:

为了更好透彻了解顺序表和链表,我们将它们比较看看!

顺序表和链表的比较

图文更加直观:

这里的缓存利用率不做过多解释,详情见:https://www.cnblogs.com/yungyu16/p/13054874.html

栈的实现--顺序表

既然是要在顺序表基础上实现栈,那么就要实现顺序表和栈的基本框架。

(单链表若有不懂的知识点,可见:通讯录的实现(顺序表版本)-CSDN博客)

stack.h文件--包含各种需要的函数

栈里面的变量:top表示栈顶下标,capacity表示栈空间。

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>typedef int STDateType;
//栈
typedef struct stack
{STDateType* a;int top;int capacity;
}ST;//栈的初始化和销毁
void STInit(ST* p);
void STDestroy(ST* p);
//入栈,出栈
void STpush(ST* p,STDateType x);
void STpop(ST* p);
//栈顶的数据
STDateType STtop(ST* p);
//栈的数据个数
int STsize(ST* p);
//判空
bool STEmpty(ST* p);

接下来我们一一实现!

初始化

我们要将栈中各个变量进行初始化。

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

栈为空的判定

我们在实现这个函数时,很多人会用 if语句来判断是否为空,但我们仔细一想,可以好好优化一下代码!

//判空
bool STEmpty(ST* p)
{assert(p);return p->top == 0;
}

入栈

经过我们刚刚的分析,入栈要在数组尾部!记得每次入栈需要判断空间是否够用哦!

void STpush(ST* p, STDateType x)
{assert(p);if (p->top == p->capacity){int newcapacity = p->capacity == 0 ? 4 : p->capacity * 2;STDateType* tmp = (STDateType*)realloc(p->a, newcapacity * sizeof(STDateType));if (tmp == NULL){perror("realloc failed!");return;}p->a = tmp;p->capacity = newcapacity;}p->a[p->top++] = x;
}

出栈

入栈要在尾部,出栈也要在尾部,后进先出的原则要时刻记住!

需要注意的是:当栈为空时,数据出不了栈!所以我们先需要判断是否为空!

void STpop(ST* p)
{assert(p);//出栈的话要判断一下空的情况assert(!STEmpty(p));p->top--;
}

销毁

我们既然用了开辟内存函数,当我们不使用栈时,要将空间释放掉!

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

栈顶数据

在访问栈顶数据时,我们也要先判断栈是否为空,否则当栈为空时,访问栈顶数据便会越界访问!

//栈顶的数据
STDateType STtop(ST* p)
{assert(p);//出栈的话要判断一下空的情况assert(!STEmpty(p));return p->a[p->top-1];
}

数据个数

//栈的数据个数
int STsize(ST* p)
{assert(p);return p->top;
}

题目操练:配括号问题

既然我们已经实现的栈,我们来应用一下吧!

题目:详情--20. 有效的括号 - 力扣(LeetCode)

思路:

遍历数组,当是左括号时("(","{","】")时就入栈,当不是左括号时就出栈比较,直到遍历完成!

这样听是不是很简单呢?当然里面没有栈,我们需要将栈创建一下!

代码:

typedef char STDateType;
//栈
typedef struct stack
{STDateType* a;int top;int capacity;
}ST;//栈的初始化和销毁
void STInit(ST* p);
void STDestroy(ST* p);
//入栈,出栈
void STpush(ST* p,STDateType x);
void STpop(ST* p);
//栈顶的数据
STDateType STtop(ST* p);
//栈的数据个数
int STsize(ST* p);
//判空
bool STEmpty(ST* p);
//栈的初始化和销毁
void STInit(ST* p)
{assert(p);p->a = NULL;p->capacity = 0;p->top = 0;
}
void STDestroy(ST* p)
{assert(p);free(p->a);p->capacity = p->top = 0;
}
//入栈,出栈
void STpush(ST* p, STDateType x)
{assert(p);if (p->top == p->capacity){int newcapacity = p->capacity == 0 ? 4 : p->capacity * 2;STDateType* tmp = (STDateType*)realloc(p->a, newcapacity * sizeof(STDateType));if (tmp == NULL){perror("realloc failed!");return;}p->a = tmp;p->capacity = newcapacity;}p->a[p->top++] = x;
}
void STpop(ST* p)
{assert(p);//出栈的话要判断一下空的情况assert(!STEmpty(p));p->top--;
}
//栈顶的数据
STDateType STtop(ST* p)
{assert(p);//出栈的话要判断一下空的情况assert(!STEmpty(p));return p->a[p->top-1];
}
//栈的数据个数
int STsize(ST* p)
{assert(p);return p->top;
}
//判空
bool STEmpty(ST* p)
{assert(p);return p->top == 0;
}
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;
}

可能有人说太麻烦了,但c语言中没有栈,只能自己创建哦!这是用目前c语言最简单的方法!

栈的实现--链表

和顺序表一样,我们首先要创建栈和链表的基本框架!

stack.h文件--包含需要的函数

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>typedef int STDataType;
//栈
typedef struct stack
{struct stcak* next;STDataType data;
}STNode;//栈的销毁
void STDestroy(STNode* phead);
//入栈
void STpush(STNode** pphead,STDataType x);
//出栈
void STpop(STNode** pphead);
//栈顶数据
STDataType STtop(STNode* phead);
//判空
bool STEmpty(STNode* phead);
//栈数据个数
int STsize(STNode* phead);

栈为空的判定

有了顺序表的基础,接下来依葫芦画瓢----最简单不过!

//判空
bool STEmpty(STNode* phead)
{return phead == NULL;
}

入栈

我们分析将链表的头部为栈顶,进出都在头!(这种方案最佳!)

//创建节点
STNode* STBuyNode(STDataType x)
{STNode* node = (STNode*)malloc(sizeof(STNode));if (node == NULL){perror("malloc failed!");return NULL;}node->data = x;node->next = NULL;return node;
}//入栈
void STpush(STNode** pphead, STDataType x)
{STNode* node = STBuyNode(x);node->next = *pphead;*pphead = node;
}

出栈

将头节点指向下一个节点,原来的头节点释放!

//出栈
void STpop(STNode** pphead)
{assert(!STEmpty(*pphead));STNode* cur = *pphead;*pphead = (*pphead)->next;free(cur);
}

销毁

同样的,动态开辟了空间,当我们不用栈时,要将开辟的空间释放掉!

//栈的销毁
void STDestroy(STNode* phead)
{STNode* cur = phead;while (cur){STNode* next = cur->next;free(cur);cur = next;}
}

栈顶数据

也是一样的,在访问栈顶数据时,要判断栈是否为空,防止越界访问!

//栈顶数据
STDataType STtop(STNode* phead)
{assert(!STEmpty(phead));return phead->data;
}

数据个数

遍历链表,将一个一个节点计数起来!

//栈数据个数
int STsize(STNode* phead)
{STNode* cur = phead;int count = 0;while (cur){count++;cur = cur->next;}return count;
}

码源--栈(顺序表)

stack.h文件

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>typedef int STDateType;
//栈
typedef struct stack
{STDateType* a;int top;int capacity;
}ST;//栈的初始化和销毁
void STInit(ST* p);
void STDestroy(ST* p);
//入栈,出栈
void STpush(ST* p,STDateType x);
void STpop(ST* p);
//栈顶的数据
STDateType STtop(ST* p);
//栈的数据个数
int STsize(ST* p);
//判空
bool STEmpty(ST* p);

stack.c文件

#include"stack.h"
//栈的初始化和销毁
void STInit(ST* p)
{assert(p);p->a = NULL;p->capacity = 0;p->top = 0;
}
void STDestroy(ST* p)
{assert(p);free(p->a);p->capacity = p->top = 0;
}
//入栈,出栈
void STpush(ST* p, STDateType x)
{assert(p);if (p->top == p->capacity){int newcapacity = p->capacity == 0 ? 4 : p->capacity * 2;STDateType* tmp = (STDateType*)realloc(p->a, newcapacity * sizeof(STDateType));if (tmp == NULL){perror("realloc failed!");return;}p->a = tmp;p->capacity = newcapacity;}p->a[p->top++] = x;
}
void STpop(ST* p)
{assert(p);//出栈的话要判断一下空的情况assert(!STEmpty(p));p->top--;
}
//栈顶的数据
STDateType STtop(ST* p)
{assert(p);//出栈的话要判断一下空的情况assert(!STEmpty(p));return p->a[p->top-1];
}
//栈的数据个数
int STsize(ST* p)
{assert(p);return p->top;
}
//判空
bool STEmpty(ST* p)
{assert(p);return p->top == 0;
}

码源--栈(链表)

stack.h文件

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>typedef int STDataType;
//栈
typedef struct stack
{struct stcak* next;STDataType data;
}STNode;//栈的销毁
void STDestroy(STNode* phead);
//入栈
void STpush(STNode** pphead,STDataType x);
//出栈
void STpop(STNode** pphead);
//栈顶数据
STDataType STtop(STNode* phead);
//判空
bool STEmpty(STNode* phead);
//栈数据个数
int STsize(STNode* phead);

stack.c文件

#include"stack.h"STNode* STBuyNode(STDataType x)
{STNode* node = (STNode*)malloc(sizeof(STNode));if (node == NULL){perror("malloc failed!");return NULL;}node->data = x;node->next = NULL;return node;
}//入栈
void STpush(STNode** pphead, STDataType x)
{STNode* node = STBuyNode(x);node->next = *pphead;*pphead = node;
}//出栈
void STpop(STNode** pphead)
{assert(!STEmpty(*pphead));STNode* cur = *pphead;*pphead = (*pphead)->next;free(cur);
}//栈顶数据
STDataType STtop(STNode* phead)
{assert(!STEmpty(phead));return phead->data;
}//判空
bool STEmpty(STNode* phead)
{return phead == NULL;
}//栈数据个数
int STsize(STNode* phead)
{STNode* cur = phead;int count = 0;while (cur){count++;cur = cur->next;}return count;
}//栈的销毁
void STDestroy(STNode* phead)
{STNode* cur = phead;while (cur){STNode* next = cur->next;free(cur);cur = next;}
}

是不是觉得今天的比较简单?好了,我们下期见!

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python实现txt文件内容对比功能

欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一.前言 二.代码 三.演示 四.代码分析 一.前言 内容对比是一种常见的信息分析和研究方法,主要涉及对不同来源、类型或版本的内容进行比

深度解析:数据结构二叉树(1)

✅作者简介&#xff1a;大家好&#xff0c;我是再无B&#xff5e;U&#xff5e;G&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a; 再无B&#xff5e;U&#xff5e;G-CSDN博客 目标 1. 掌握树的基本概念 2. 掌握二叉…

[NSSRound#1 Basic]basic_check

[NSSRound#1 Basic]basic_check 开题什么都没有&#xff0c;常规信息搜集也无效 发现题目允许PUT的两种做法&#xff1a; 1、 CURL的OPTIONS请求方法查看允许的请求方式 curl -v -X OPTIONS http://node4.anna.nssctf.cn:28545/index.php2、 kali自带的nikto工具扫描网址 Nik…

盘点十款企业电脑监控软件的功能及优势

企业电脑监控软件是专为企业环境设计的工具&#xff0c;用于监视员工的电脑使用情况&#xff0c;以确保安全性、生产力和合规性。以下是一些常见的企业电脑监控软件&#xff0c;以及它们的功能和优势&#xff1a; 1、Ping32&#xff1a; 功能&#xff1a;网站访问监控、即时通…

1-3ARM_GD32点亮LED灯

简介&#xff1a; 最多可支持 112 个通用 I/O 引脚(GPIO)&#xff0c;分别为 PA0 ~ PA15&#xff0c;PB0 ~ PB15&#xff0c;PC0 ~ PC15&#xff0c;PD0 ~ PD15&#xff0c;PE0 ~ PE15&#xff0c;PF0 ~ PF15 和 PG0 ~ PG15&#xff0c;各片上设备用其来实现逻辑输入/输出功能。…

在类设计器中使用 C++ 代码其中模板类、结构、Enum、宏、Typedef

类设计器支持以下 C 代码元素 &#xff1a; 模板类 结构 Enum 宏&#xff08;显示宏的处理后视图&#xff09; Typedef 模板类 类设计器支持直观显示模板类 。 支持嵌套声明。 下表列出了一些典型声明。 展开表 Code 元素类设计器视图template <class T>class A {};…

vue+element的表格(el-table)排班情况表(2024-05-09)

vueelement的表格&#xff08;el-table&#xff09;排班情况&#xff0c;增删查改等简单功能 代码&#xff1a; <template><!-- 表格 --><div class"sedules"><el-header><el-date-pickerv-model"monthValue2"type"month…

亚马逊是如何铺设多个IP账号实现销量大卖的?

一、针对亚马逊平台机制&#xff0c;如何转变思路&#xff1f; 众所周知&#xff0c;一个亚马逊卖家只能够开一个账号&#xff0c;一家店铺&#xff0c;这是亚马逊平台明确规定的。平台如此严格限定&#xff0c;为的就是保护卖家&#xff0c;防止卖家重复铺货销售相同的产品&a…

即将开幕,邀您共赴创新之旅“2024上海国际消费者科技及创新展览会”

备受期待的2024上海国际消费者科技及创新展览会&#xff08;以下简称“CTIS”&#xff09;即将于6月13日至15日亮相上海新国际博览中心N1-N3馆。 2024上海国际消费者科技及创新展览会总面积达40,000平方米&#xff0c;涵盖600余家展商&#xff0c;预计吸引40,000多位观众莅临现…

漫威争锋Marvel Rivals怎么搜索 锁区怎么搜 游戏搜不到怎么办

即将问世的《漫威争锋》&#xff08;Marvel Rivals&#xff09;作为一款万众期待的PvP射击游戏新星&#xff0c;荣耀携手漫威官方网站共同推出。定档5月11日清晨9时&#xff0c;封闭Alpha测试阶段将正式揭开序幕&#xff0c;持续时间长达十天之久。在此首轮测试窗口&#xff0c…

Fortinet的安全愿景SASO概述

FTNT SASE的独特方法&#xff0c;使其成为一家适应性极强的厂商&#xff0c;能够应对不断变化的网络和网络安全环境。FTNT开发了一种名为Secure Access Service Omni&#xff08;SASO&#xff09;的变体&#xff0c;以更准确地反映FTNT在融合网络和安全功能方面的实力。我们预计…

nginx 启动,查看,停止

nginx 启动&#xff0c;查看&#xff0c;停止 启动 start nginx 查看是否启动成功 tasklist | findstr nginx 停止 nginx -s stop 测试配置文件的语法是否有误 nginx -t 重启nginx nginx-s reload