本文主要讨论C语言数据结构的又一重要结构——栈

一、栈的理论知识

1. 定义和特点

定义:只允许在一端插入和删除的线性表;允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom)。
特点:后进先出 (LIFO)

栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。它照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。
​使用通俗的话语形容就像压入子弹夹的子弹,先压入的反而在后面击发出去;

2.栈的主要C语言操作

int Push (stack S, StackData x); //进栈,stackS指针域,StackData x数据域
int Pop (stack *S, StackData &x); //出栈
int GetTop (stack *S, StackData &x); //取栈顶
void InitStack (stack *S); //置空栈
int StackEmpty (stack *S); //判栈空否
int StackFull (stack *S); //判栈满否

3.栈的具体图示

  • 入栈

  • 在进栈之前要先检查是否是空栈

  • 出栈

退栈之前也要检查是否空栈
就好比手持步枪与敌人拼杀时,射击之前必须要确定膛内是否有子弹可以击杀敌人;与敌人拼刺刀时要检查膛内子弹是否退完避免误伤队友

二、栈的实现

由表的分类自然而然地可以联想到栈可以分类为顺序栈及链式栈两类

使用简单的例子进行示例,大多数链表建立的过程可表示为以下过程,而栈,队列的建立,大体结构也可以依此建立
——————————————————
类型名 : 简单链表
类型属性: 可以储存的一系列项
类型操作: 1、初始化链表
————— 2、确定链表为空
————— 3、确定链表已满
————— 4、确定链表中项数
————— 5、在链表末尾添加项
————— 6、遍历链表,处理链表中的项
————— 7、清空链表
————————————————————

1. 顺序栈

头文件及结构体定义

#include<stdio.h>
#include<stdlib.h>
#define SIZE 10enum ret_val{FULL_OK=100,FULL_NO,EMPTY_OK,EMPTY_NO,PUSH_OK,PUSH_NO,POP_OK,POP_NO};
//枚举在“枚举”类型的定义中列举出所有可能的取值,
//在枚举值表中应罗列出所有可用值。这些值也称为枚举元素struct stack_node //定义一个栈结构体
{int stack_data[SIZE]; //定义栈的大小int top;  //定义栈顶
};typedef struct stack_node Stack;  //typedef的作用是为已有的数据类型定义一个新名字,
//方便后面写起来简单

分配内存空间及设置栈顶

void create_stack(Stack **stack)
{*stack = (Stack *)malloc(sizeof(Stack));  //让栈点指向新建节点创建的内存空间
}void init_stack(Stack * stack)
{stack->top = -1; //定义栈顶,为判断栈是否为空作准备
}

进栈

int is_full(Stack * stack)   //定义进栈的判断值,
//判断是否进栈
{if(stack->top >=SIZE)  //判断栈是否为空{return FULL_OK;}return FULL_NO;
}int push_stack(Stack *stack ,int num) //进栈数值(即第几次进栈)
{if (FULL_NO == is_full(stack)){//stack->top++;stack->stack_data[++stack->top]  = num;  //栈顶加一,进栈成功return PUSH_OK;}printf("stack is full!\n");return PUSH_NO;
}

出栈

int is_empty(Stack * stack)   //定义出栈的判断值
//判断是否出栈
{if(stack->top == -1)  //判断栈是否为空{printf("stack is empty!\n");return EMPTY_OK;}return EMPTY_NO;
}int pop_stack(Stack *stack ) //出栈数值
{if (EMPTY_NO == is_empty(stack)){return stack->stack_data[stack->top--] ;  //栈顶减一,出栈成功}else{return POP_NO;       }
}

主函数

int main()
{Stack * stack = NULL;  //野指针int i;int num;create_stack(&stack);init_stack(stack);for (i = 0; i < 10; i++)    //入栈的具体操作{if (PUSH_OK == push_stack(stack,i+1)){printf("push stack success!\n");}else{printf("push stack fail!\n");}}for (i = 0; i < 15; i++)      //出栈的具体操作{num =pop_stack(stack);if (POP_NO != num)     //pop_stack(stack){printf("%d\n",num);}else{printf("pop stack fail!\n");}}free(stack);     //释放分配的栈空间return 0;
}

2、链式栈

链式栈无栈满问题,空间可扩充
插入与删除仅在栈顶处执行
链式栈的栈顶在链头
适合于多栈操作

头文件及结构体定义

#include <stdio.h>
#include <stdlib.h>
#include <string.h>struct node   //定义链表节点
{int num;char name[20];struct node *next;
};struct node_stack    //定义栈
{int num;       //char name[20];
};typedef struct node * Link;
typedef struct node_stack Stack;enum result {MALLOC_OK = 100,MALLOC_NO,EMPTY_OK,EMPTY_NO,PUSH_OK,PUSH_NO,POP_NO,POP_OK};

分配空间及设置判定

int  create_node(Link * new_node)  //创建链式栈,让指针指向栈
{*new_node = (Link)malloc(sizeof(struct node));     //让栈节点指向新建节点创建的内存空间if(*new_node == NULL)    //判断内存空间是否创建成功{printf("malloc error!\n");return MALLOC_NO;}return MALLOC_OK;
}void create_stack(Link *stack)   //定义栈,复查链式栈
{int ret;ret = create_node(stack);  //承接创建成功的标准,拿这个去对比,//就好比二分类,1是男,0是女,出现什么数字就判断为什么性别if(ret == MALLOC_NO)  //判断链式栈是否创建成功{printf("create stack fail!\n");exit(-1);}(*stack)->next = NULL;   //创建栈头(节点)设置为空
}

进栈

int push_stack(Link stack,Stack node)  //进栈
{Link new_node;int ret;ret = create_node(&new_node);if(ret == MALLOC_NO)  //判断栈是否为空{printf("push error!\n");return PUSH_NO;}//p->data (结构体里变量)= data(输入的数据);new_node->num = node.num;    strcpy(new_node->name,node.name);//p->next (插入节点的后继指针)=(指向) top->next(头节点的后继指针);new_node->next = stack->next;  //top->next (头节点的后继指针)= p(插入的节点);stack->next = new_node;   return PUSH_OK;
}

出栈


int is_empty(Link stack)  //定义出栈的判断值
{if(stack->next == NULL)   //判断栈是否为空{printf("stack is empty!\n");return EMPTY_OK;}return EMPTY_NO;
}int pop_stack(Link stack,Stack * node)  //出栈
{Link p;p = stack->next;  //在栈后插入节点if(is_empty(stack) == EMPTY_OK){return POP_NO;}else{//将结构体里的变量还给节点;node->num = p->num;strcpy(node->name,p->name);stack->next = p->next;  //头节点的后继指针指向被删除节点的后继指针free(p); //释放p的空间return POP_OK;}
}

主函数

int main()
{Link stack;Stack node;int i;int ret;create_stack(&stack);for(i = 0;i < 5; i++){node.num = i + 1;scanf("%s",node.name);  //输入数据域中的内容push_stack(stack,node);}for(i = 0; i < 5;i++){ret = pop_stack(stack,&node);if(ret == POP_NO){printf("POP fail!\n");}else{printf("num = %d\n",node.num);//输出数据域中的内容printf("name is :%s\n",node.name);}}return 0;
}

三、栈的一个小应用

栈在表达式计算过程中的应用

实际上就例如(a+b)*c(这里只考虑加减乘除和括号这几个符号)这样一个表达式,你怎么用栈来进行计算
首先新建两个栈(链式栈的优点),一个储存数字,一个储存运算符
数字一律进栈,字符需要考虑运算级,两个运算符先后进栈,比较,等级高的进栈,低的,先计算该运算符然后把计算好的数字代替运算符两侧的数字进栈,该运算符不进栈
左括号一律进运算符栈,右括号一律不进运算符栈,取出运算符栈顶运算符和操作数栈顶的两个操作数进行运算,并将结果压入操作数栈,直到取出左括号为止。

头文件及结构体

#include<stdio.h>
#include<stdlib.h>#define MAX 100struct operand  //定义第一个栈结构体,存储数字
{int data[MAX];  //定义栈元素数组int top;  //定义栈顶
};struct operator_ch  //定义第二个栈,存储运算符
{int top;char data[MAX];
};typedef struct operand OPND; //重定义
typedef struct operator_ch OPCH;

分配空间及设置判定

void init_OPND_stack(OPND*stack)
//void表示空类型,它跟int,float是同地位的,
//一般用在没有返回值的函数中
{stack->top = -1;
}void init_OPCH_stack(OPCH*stack) //初始化函数
{stack->top= -1;  //定义栈顶,为判断是否为空作准备
}int is_empty_OPND(OPND*stack) //定义判断数字栈为空的函数
{if (stack->top == -1){return -1;}return 0;
}int is_empty_OPCH(OPCH*stack)  //定义判断字符栈为空的函数
{if (stack->top == -1){return -1;}return 0;
}int get_OPND_top(OPND*stack)  //定义数字栈的判断函数
{if (is_empty_OPND(stack) == -1){return -1;}return stack->data[stack->top];  //形似a[],返回栈数组的值
}char get_OPCH_top(OPCH*stack)  //定义字符栈的判断函数
{if (is_empty_OPCH(stack) == -1){return -1;}return stack->data[stack->top];  //形似a[],返回栈数组的值
}

进出栈函数

void push_OPND(OPND*stack,int num)  //定义数字栈进栈函数
{stack->data[++(stack->top)] = num;printf("push%d\n",stack->data[stack->top]);}void push_OPCH(OPCH*stack,char ch)  //定义字符栈进栈函数
{stack->data[++(stack->top)] = ch;}int pop_OPND(OPND*stack)   //定义函数栈出栈函数
{if (is_empty_OPND(stack)  == -1){return -1;}int num = stack->data[stack->top];(stack->top)--;return num;
}char pop_OPCH(OPCH*stack)  //定义字符栈出栈函数
{if (is_empty_OPCH(stack)  == -1){return -1;}char ch = stack->data[stack->top];(stack->top)--;return ch;
}

获得字符函数及表达式函数

int get_priority(char ch)  //定义获得字符函数
{if (ch == '+'  ||  ch == '-'){return 1;}if (ch == '*'  ||  ch  == '/'){return 2;   }}int compare_priority(char op_ch,char ch)  //定义比较字符优先级的函数
{if (get_priority(op_ch)>=get_priority(ch)){return 1;}return -1;
}int count(int a,int b,char ch)  //定义计算表达式的函数
{int result;switch(ch){case '+':{result = a+b;break;}case '-':{result = a-b;break;}case '*':{result = a*b;break;}case '/':{result = a/b;break;}}return result;
}

主函数

int main()  //主函数
{char ch;char op_ch;int a,b;int opr_num;int result_cal;OPND * opnd_stack;OPCH * opch_stack;opnd_stack = (OPND *)malloc(sizeof(OPND));  //分配内存空间opch_stack = (OPCH *)malloc(sizeof(OPCH));init_OPND_stack(opnd_stack);  //初始化栈init_OPCH_stack(opch_stack);while((ch = getchar()) != '\n')  //从栈里取字符{if(ch >= '0' && ch <= '9')   //数字入栈{// push_stack1();opr_num = ch - '0';push_OPND(opnd_stack,opr_num);}else{if(ch == '+' || ch == '-' || ch == '*' || ch == '/')   {//op_ch = pop_stack2();do{op_ch = get_OPCH_top(opch_stack);   //得到栈顶元素if(op_ch == -1)   //如果栈顶元素为空{push_OPCH(opch_stack,ch);  //字符入栈break;}else{if(compare_priority(op_ch,ch) < 0)   //如果先前字符优先级小于新进运算符优先级,输入新进运算符{//    push_stack2(ch);push_OPCH(opch_stack,ch);break;}else{a = pop_OPND(opnd_stack);b = pop_OPND(opnd_stack);op_ch = pop_OPCH(opch_stack);if(a == -1 || b == -1 || op_ch == -1)   //如果数字栈或字符栈其中一个为空,输出栈为空{printf("stack is empty!\n");}//   printf("%d%c%d",a,op_ch,b);// printf("\n");result_cal = count(b,a,op_ch);push_OPND(opnd_stack,result_cal);   //已计算的结果进栈}}}while(compare_priority(op_ch,ch) > 0);//  push_OPCH(opch_stack,ch);}}}  //第一遍计算,只是把数字和字符入栈,没有计算总结果while(is_empty_OPND(opnd_stack) != -1 && is_empty_OPCH(opch_stack) != -1)  {a = pop_OPND(opnd_stack);b = pop_OPND(opnd_stack);op_ch = pop_OPCH(opch_stack);result_cal = count(b,a,op_ch);push_OPND(opnd_stack,result_cal);  //两个栈都不为空时,计算总结果并入栈}
//  printf("%d%c%d",a,op_ch,b);
//  printf("\n");printf("result is %d\n",result_cal);free(opnd_stack); //释放栈空间free(opch_stack);return 0;
}

C语言数据结构-栈的使用及实例相关推荐

  1. 11.0、C语言数据结构——栈

    11.0.C语言数据结构--栈 栈的定义:         栈是一种重要的线性结构,可以这样讲,栈是前面讲过的线性表的一种具体形式:         官方定义:栈(stack)是一个 后进先出(Las ...

  2. c语言特殊计算器设计报告,C语言数据结构栈计算器的实现课题设计报告书

    C语言数据结构栈计算器的实现课题设计报告书 (13页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 14.9 积分 目录1. 课程设计任务 12. 需求分析 ...

  3. c语言栈中符号 的作用是什么,C语言数据结构----栈的应用(程序的符号匹配检测)...

    本节主要讲利用栈来实现一个程序中的成对出现的符号的检测,完成一个类似编译器的符号检测的功能,采用的是链式栈. 一.问题的提出以及解决方法 1.假定有下面一段程序: #include #include ...

  4. C语言-数据结构-栈(静态栈与动态栈)

    一.简介 在哔哩哔哩看视频学的,赫斌老师数据结构入门的内容-b站搜索:av6159200(P33),通过学习,能独立把赫斌老师教的敲出来,由于动态栈(链表阉割版)的功能很少,我并没有增加什么其它功能, ...

  5. [C语言数据结构]栈

    目录 1.栈的定义: 1.2栈的特性: 1.3栈的实现: 1.4代码: 1.4.1结构的声明: 1.4.2栈的初始化: 代码: 1.4.3入栈: 代码: 1.4.4出栈 void StackPop(S ...

  6. C语言 数据结构 栈的数组实现 realloc函数

    主题:栈的数组实现 功能:分别栈的入栈.弹栈.打印操作 提示:运行程序自动进入入栈操作,退出入栈,数组3个ctrl z,然后进入出栈操作,输入非n的任意char字符,继续出栈.输入n结束出栈,整个程序 ...

  7. C语言 数据结构 栈(用链表实现)

    疑惑 为什么栈要分两个结构体来创建,而链表只需要一个? 能不能只用一个结构体创建一个栈? 代码 用函数实现了压栈,弹栈,打印栈的操作 #include<stdio.h> #include& ...

  8. GO语言-数据结构-栈

    目录 1.栈的顺序存储实现 1.1结构体定义 1.2 初始化栈 1.3入栈 1.4出栈 1.5完整代码 1.6拓展-一个数组实现两个栈 2.栈的链式存储实现 2.1链栈的结构体定义 2.2链栈的初始化 ...

  9. C语言 数据结构 栈的应用(括号匹配)

    #include<stdio.h> #include<stdlib.h> #define MaxSize 10 #define true 1 #define false 0 t ...

最新文章

  1. 清华滴滴:出行数据透视中国城市空间发展报告!
  2. 《树莓派开发实战(第2版)》——2.8 利用VNC远程控制树莓派
  3. Java8新特性之构造器引用、方法引用
  4. zabbix监控oracle缓冲区,Zabbix监控oracle各服务器连接数
  5. jquery 获取id最大的元素_超全整理!JQuery中的选择器集合
  6. ​.NET手撸2048小游戏
  7. 【VB测绘程序设计】第二章 VB测绘程序基础
  8. 你所坚信的,就是你的生活
  9. Java归去来第3集:Eclipse中给动态模块升级
  10. java操作mysql实例 让代码跑起来
  11. SmartPhone和PPC手机的区别
  12. 呼吸机吸气触发:压力触发与流量触发
  13. 项目管理49个过程超详细总结(持续更新中)
  14. [代码审计]DuxCMS 2.0审计
  15. 11_4 PTB数据预处理
  16. PRN(20200908):Frosting Weights for Better Continual Training
  17. 应用礼学赋能新员工职业素养提升
  18. 基于BLE + LoRa人员定位技术下的室内定位-Lora人员定位-新导智能
  19. 为什么黑客几乎不用鼠标?
  20. 自制合成孔径雷达(3) doppler代码解读

热门文章

  1. 用Python手写十大经典排序算法
  2. Java实现类似于Redis一样的缓存
  3. 鸟哥的Linux私房菜(基础篇)-第三章、主机规划与磁盘分区(三.2. 磁盘分区)
  4. 海南省澄迈县谷歌卫星地图下载
  5. DTO 与 PO的相互转换
  6. 凡客体,是这样的么【人人都是产品经理:9094】
  7. yolov5最新版本预训练模型下载
  8. 如何正确有效的进行滑环的安装
  9. Android基本控件之RadioGroup(实现选中互斥功能)
  10. 苹果悬浮球_谁说苹果手机的悬浮球不好用的!那是你没有了解它的真正用法