数据结构-------栈

news/2025/3/28 15:27:53/

顺序栈:

一、数据结构定义

  1. 数据元素 DATATYPE
typedef struct person {char name[32];char sex;int age;int score;
} DATATYPE;
  1. 顺序栈结构 SeqStack
typedef struct list {DATATYPE *head;  // 栈空间首地址int tlen;        // 栈总容量(total length)int top;         // 栈顶指针(相当于当前元素计数)
} SeqStack;

二、核心操作接口

  1. 创建栈
SeqStack *CreateSeqStack(int size)
{SeqStack *ss = malloc(sizeof(SeqStack));if (NULL == ss){perror("CreateSeqStack malloc error\n");return NULL;}ss->head = malloc(sizeof(DATATYPE) * size);if (NULL == ss){perror("CreateSeqStack malloc2 error\n");return NULL;}ss->tlen = size;ss->top = 0;return ss;
}
  • 实现要点:
    • 动态分配结构体内存
    • 分配连续存储空间:head = malloc(size * sizeof(DATATYPE))
    • 初始化tlen = sizetop = 0
  1. 销毁栈
int DestroySeqStack(SeqStack *ss)
{if (NULL == ss){fprintf(stderr, "DestroySeqStack pamter error\n");return 1;}free(ss->head);free(ss);return 0;
}
  • 内存释放顺序:
    1. 释放数据空间 free(ss->head)
    2. 释放控制结构 free(ss)
  1. 入栈操作
int PushSeqStack(SeqStack *ss, DATATYPE *data) // add
{if (NULL == ss || NULL == data || IsFullSeqStack(ss)){fprintf(stderr, "PushSeqStack pamter error\n");return 1;}memcpy(&ss->head[ss->top], data, sizeof(DATATYPE));ss->top++;return 0;
}
  • 实现流程:
if 栈未满:复制数据到ss->head[top]位置top++返回成功
else:返回失败
  1. 出栈操作
int PopSeqStack(SeqStack *ss)
{if (NULL == ss){fprintf(stderr, "PopSeqStack pamter error\n");return 1;}ss->top--;return 0;
}
  • 实现逻辑:
if 栈非空:top--返回成功
else:返回失败
  1. 判空操作
int IsEmpySeqStack(SeqStack *ss)
{return 0 == ss->top;
}
  • 判断条件:top == 0
  1. 判满操作
int IsFullSeqStack(SeqStack *ss)
{return ss->tlen == ss->top;
}
  • 判断条件:top == tlen
  1. 获取栈顶元素
DATATYPE *GetTopSeqStack(SeqStack *ss)
{if (NULL == ss || IsEmpySeqStack(ss)){fprintf(stderr, "GetTopSeqStack pamter error\n");return NULL;}return &ss->head[ss->top - 1];
}
  • 注意点:
    • 返回ss->head[top-1]的地址
    • 需先判断栈是否为空
  1. 获取栈大小
int GetSizeSeqStack(SeqStack *ss)
{if (NULL == ss ){fprintf(stderr, "GetSizeSeqStack pamter error\n");return 1;}return ss->top;
}
  • 直接返回top

三、存储结构示意图

栈底 → head[0]head[1]...
栈顶 → head[top-1]  ← 当前有效元素head[top]    ← 下一个可用位置(当top<tlen时)...head[tlen-1]

四、时间复杂度分析

操作时间复杂度说明
创建栈O(1)内存分配操作
销毁栈O(1)内存释放操作
入栈/出栈O(1)直接操作栈顶指针
获取栈顶元素O(1)随机访问特性
获取栈大小O(1)直接读取top值

五、优势与局限

  1. 优势

    • 随机访问特性,支持快速定位
    • 内存连续,缓存命中率高
    • 操作时间复杂度均为O(1)
  2. 局限

    • 固定容量,需要预先分配空间
    • 扩容成本高(需要重新分配内存)
    • 可能产生空间浪费(分配未使用的空间)

六、典型应用场景

  1. 函数调用栈的实现
  2. 表达式求值(中缀转后缀表达式)
  3. 括号匹配检测
  4. 浏览器的后退操作栈
  5. 撤销/重做功能实现

七、实现注意事项

  1. 内存管理

    • 创建时需分配两次内存(控制结构+数据空间)
    • 销毁时需按相反顺序释放
  2. 临界条件处理

    • 入栈前必须检查栈是否已满
    • 出栈前必须检查栈是否为空
    • 获取栈顶元素前必须检查非空

八、实际应用

1.符号匹配

main 函数

#include "./SeqStack.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int do_check(char *buf, SeqStack *ss, int num)
{int col = 1;DATATYPE data;while (*buf){DATATYPE *tmp = NULL;bzero(&data, sizeof(data));int c = *buf;switch (c){case '(':case '[':case '{':handle_left_bracket(c, num, col, &data, ss);break;case ')':case ']':case '}':if (handle_right_bracket(c, num, col, ss)){return 1;}break;}buf++;col++;}return 0;
}// 封装左括号的处理逻辑
void handle_left_bracket(int c, int num, int col, DATATYPE *data, SeqStack *ss)
{data->sym = c;data->linenum = num;data->colnum = col;PushSeqStack(ss, data);
}// 封装右括号的处理逻辑
int handle_right_bracket(int c, int num, int col, SeqStack *ss)
{DATATYPE *tmp = GetTopSeqStack(ss);if (tmp == NULL){printf("read sym:%c ,line:%d col:%d\n", c, num, col);return 1;}if ((c == ')' && tmp->sym == '(') ||(c == ']' && tmp->sym == '[') ||(c == '}' && tmp->sym == '{')){PopSeqStack(ss);return 0;}else{printf("read sym:%c ,line:%d col:%d  or top sym:%c ,line:%d col:%d\n", c, num, col, tmp->sym, tmp->linenum, tmp->colnum);return 1;}
}
int main(int argc, char const *argv[])
{SeqStack *ss = CreateSeqStack(5);FILE *fp = fopen("./open.c", "r+");if (NULL == fp){perror("fopen");return 1;}int num = 1;int ret = 0;while (1){char buf[256] = {0};if (NULL == fgets(buf, sizeof(buf), fp)){break;}ret = do_check(buf, ss, num);if(1== ret){DestroySeqStack(ss);exit(1);}num++;/* code */}if(IsEmpySeqStack(ss)){printf("file ok\n");}else{DATATYPE *tmp = GetTopSeqStack(ss);printf("top sym:%c ,line:%d col:%d\n", tmp->sym, tmp->linenum, tmp->colnum);}return 0;
}

2.四则运算(栈)

int applyOperator(int a, int b, char op)
{switch (op){case '+':return a + b;case '-':return a - b;case '*':return a * b;case '/':return a / b;default:fprintf(stderr, "applyOperator error\n");return 0;}
}
int precedence(char op)
{if (op == '+' || op == '-'){return 1;}if (op == '*' || op == '/'){return 2;}return 0;
}
int evaluateExpression(char *expression)
{SeqStack *operand = CreateSeqStack(100);SeqStack *opertor = CreateSeqStack(100);int i = 0;while (expression[i] != '\0'){char c = expression[i];if (isdigit(c)){int num = 0;while (isdigit(expression[i])){num = num * 10 + (expression[i] - '0');i++;}DATATYPE data;data.op = '0';data.num = num;PushSeqStack(operand, &data);}else if (c == '+' || c == '-' || c == '*' || c == '/'){while (!IsEmpySeqStack(opertor) && precedence(c) <= precedence(GetTopSeqStack(opertor)->op)){DATATYPE opData = *GetTopSeqStack(opertor);PopSeqStack(opertor);DATATYPE bData = *GetTopSeqStack(operand);PopSeqStack(operand);DATATYPE aData = *GetTopSeqStack(operand);PopSeqStack(operand);int ret = applyOperator(aData.num, bData.num, opData.op);DATATYPE retData;retData.op = '0';retData.num = ret;PushSeqStack(operand, &retData);}DATATYPE data;data.op = c;PushSeqStack(opertor, &data);i++;}else{i++;}}// 处理运算符栈中剩余的运算符while (!IsEmpySeqStack(opertor)){DATATYPE opData = *GetTopSeqStack(opertor);PopSeqStack(opertor);DATATYPE bData = *GetTopSeqStack(operand);PopSeqStack(operand);DATATYPE aData = *GetTopSeqStack(operand);PopSeqStack(operand);int ret = applyOperator(aData.num, bData.num, opData.op);DATATYPE retData;retData.op = '0';retData.num = ret;PushSeqStack(operand, &retData);}int result = GetTopSeqStack(operand)->num;DestroySeqStack(operand);DestroySeqStack(opertor);return result;
}

链式栈(Linked Stack)


一、链式栈核心结构

1. 节点定义
// 数据元素类型
typedef struct person {char name[32];char sex;int age;int score;
} DATATYPE;// 栈节点结构
typedef struct stacknode {DATATYPE data;           // 数据域struct stacknode *next;  // 指针域
} LinkStackNode;// 栈管理结构
typedef struct list {LinkStackNode *top;      // 栈顶指针int clen;                // 当前元素个数
} LinkStack;

二、核心操作实现

1. 创建空栈
LinkStack*CreateLinkStack()
{LinkStack* ls = malloc(sizeof(LinkStack));if(NULL == ls){perror("CreateLinkStack malloc error\n");return NULL;}ls->top = NULL;ls->clen = 0;return ls;}
2. 销毁栈
int DestroyLinkStack(LinkStack*ls)
{if(NULL == ls ){fprintf(stderr,"DestroyLinkStack paramter error\n");return 1;}while(!IsEmptyLinkStack(ls)){PopLinkStack(ls);}free(ls);return 0;
}

三、栈操作实现

1. 入栈操作
int PushLinkStack(LinkStack*ls,DATATYPE*data)
{if(NULL == ls || NULL == data){fprintf(stderr,"PushLinkStack paramter error\n");return 1;}LinkStackNode* newnode = malloc(sizeof(LinkStackNode));if(NULL == newnode){perror("PushLinkStack malloc error\n");return 1;}memcpy(&newnode->data,data,sizeof(DATATYPE));newnode->next = NULL;if(IsEmptyLinkStack(ls)){ls->top = newnode;}else {newnode->next = ls->top;ls->top = newnode;}ls->clen++;return 0;}
2. 出栈操作
int PopLinkStack(LinkStack*ls)
{if(NULL == ls  ){fprintf(stderr,"PopLinkStack paramter error\n");return 1;}if(IsEmptyLinkStack(ls)){fprintf(stderr,"PopLinkStack empty\n");return 1;}LinkStackNode* tmp = ls->top;ls->top = ls->top->next;free(tmp);ls->clen--;return 0;}

四、辅助操作实现

1. 判空检测
int IsEmptyLinkStack(LinkStack* ls) {return ls->clen == 0;// 或 return ls->top == NULL;
}
2. 获取栈顶元素
DATATYPE*GetTopLinkStack(LinkStack*ls)
{if(NULL == ls  ){fprintf(stderr,"GetTopLinkStack paramter error\n");return NULL;}if(IsEmptyLinkStack(ls)){fprintf(stderr,"GetTopLinkStack empty\n");return NULL;}return &ls->top->data;
}
3. 获取栈大小
int GetSizeLinkStack(LinkStack* ls) {return ls->clen;
}

五、链式栈 VS 顺序栈

对比维度链式栈顺序栈
存储结构离散内存节点连续内存空间
容量限制动态扩展固定大小
内存开销每个节点含指针(+8/16字节)无额外开销
入栈操作动态分配内存可能需扩容
缓存友好性较差优秀
实现复杂度需处理指针操作数组索引操作简单

六、典型应用场景

1. 函数调用栈
void funcA() {// 保存当前上下文入栈funcB();// 弹出上下文
}void funcB() {// 新的栈帧入栈
}
2. 表达式求值
// 中缀转后缀表达式算法
while(输入队列不为空) {读取token;if(是数字) 加入输出队列;else if(是运算符) {while(栈顶运算符优先级 >= 当前运算符)弹出栈顶到输出队列;当前运算符入栈;}
}
3. 括号匹配检测
bool isValid(char* s) {LinkStack *ls = CreateLinkStack();while(*s) {if(*s == '(' || *s == '[' || *s == '{') {PushLinkStack(ls, *s);} else {if(IsEmptyLinkStack(ls)) return false;char top = GetTopLinkStack(ls);if((*s == ')' && top != '(') ||(*s == ']' && top != '[') ||(*s == '}' && top != '{')) return false;PopLinkStack(ls);}s++;}return IsEmptyLinkStack(ls);
}


http://www.ppmy.cn/news/1582822.html

相关文章

2025最新正版Autodesk 3ds Max 2022安装教程:从下载到中文环境配置全流程解析

一、软件简介 Autodesk 3ds Max 2022是一款专业的三维建模、动画和渲染软件&#xff0c;广泛应用于影视制作、游戏开发、建筑可视化等领域。其核心功能包括&#xff1a; 智能建模工具&#xff1a;增强的挤出、切片、对称修改器等高效渲染引擎&#xff1a;集成Arnold渲染器&am…

3.20-1ui自动化切换,登录退出

from selenium import webdriver #导入selenium模块中的webdriver from selenium.webdriver.common.action_chains import ActionChains import time dxwebdriver.Chrome() #创建一个驱动谷歌浏览器的对象# dx.get("https://www.baidu.com") #通过get打开页面…

【前端 vue 或者麦克风,智能语音识别和播放功能】

前端 vue 或者麦克风&#xff0c;智能语音识别和播放功能 1. 终端安装 npm install recordrtc2.引入 import RecordRTC from recordrtc3.html&#xff08;根据自己业务更改&#xff09; <div class"Page"><el-form ref"mainFormRef" class&qu…

CE设备(Customer Edge device,用户边缘设备)

CE设备&#xff08;Customer Edge device&#xff0c;用户边缘设备&#xff09;是指在服务提供商网络与客户网络之间的边界设备&#xff0c;它属于客户所有并管理。CE设备的主要功能是连接客户网络到服务提供商的网络&#xff0c;如互联网服务提供商&#xff08;ISP&#xff09…

vue3怎么定义计算属性

在 Vue 3 中&#xff0c;你可以使用 computed 函数来定义计算属性。computed 函数来自 Vue 3 的组合式 API&#xff0c;它有两种使用方式&#xff1a;只读计算属性和可写计算属性&#xff0c;下面分别介绍这两种方式。 只读计算属性 只读计算属性是最常见的用法&#xff0c;它…

SQL Server 数据库引擎服务实例功能出错的解析与解决方案

SQL Server 是 Microsoft 开发的一款关系型数据库管理系统。虽然它的功能强大&#xff0c;但在实际使用过程中&#xff0c;用户可能会遇到“SQL Server 数据库引擎服务实例功能出错”的问题。本文将对此进行剖析&#xff0c;并提供相应的解决方案。 一、错误的常见原因 服务未启…

​ 《Keras 3 :开发人员指南 / 迁移学习和微调​》

​《Keras 3 &#xff1a;开发人员指南 / 迁移学习和微调​》 迁移学习和微调 作者&#xff1a;fchollet 创建日期&#xff1a;2020/04/15 最后修改时间&#xff1a;2023/06/25 描述&#xff1a;Keras迁移学习和微调的完整指南。 在 Colab 中查看 GitHub 源 设置 import numpy…

Go语言中context.Context的

context.Context 是 Go 语言中用于管理请求生命周期、传递请求范围数据以及控制超时和取消的核心接口。它在并发编程、网络请求、微服务等场景中非常重要。以下是对 context.Context 的详细解释&#xff1a; 1. context.Context 的作用 context.Context 的主要作用包括&#x…