数据结构与算法学习笔记(C语言)

链栈

在开始链栈的学习之前,我们先实现一下上一篇文章中提到的检查括号匹配的小程序,鉴于水平有限,本人就随便写一下代码好了,目标仅限于对功能的实现。

/*用顺序栈这种数据结构,实现一个检查括号匹配的小程序*/
/*头文件*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>/*定义类型*/
typedef char SElemType;
typedef int Status;/*定义状态码*/
#define OK 1
#define ERROR 0
#define OVERFLOW -2/*顺序栈的C定义*/
#define INIT_SIZE 100 //存储空间初始分配量
#define INCREMENT 10 //存储空间分配增量
typedef struct {SElemType *base; //存储空间基址SElemType *top;    //栈顶指针int stacksize; //当前已分配的存储空间
}SqStack;/*所需要的函数原型的声明*/
void Match_Check(); /*匹配检查函数*/
Status InitStack(SqStack *S); /*初始化栈函数*/
bool Is_Empty(SqStack); /*判断栈中是否有元素*/
Status GetTop(SqStack S, SElemType *e); /*取栈顶元素函数*/
Status Push(SqStack *S, SElemType e); /*压栈函数*/
Status Pop(SqStack *S, SElemType *e);/*弹栈函数*/int main(void)
{/*在主函数中调用匹配检查函数*/Match_Check();return 0;
} /*匹配检查函数的实现*/
/*请用英文输入法输入文本以及括号,所写的程序中用来检查的括号是英文括号*/
void Match_Check()
{SqStack S; SElemType e; bool Is_Match = true; int ch;/*没有字符输入的时候,先假定是括号是匹配的*/InitStack(&S);printf("请输入一段文本:\n");while ((ch = getchar()) != EOF && Is_Match) {/*从括号失配开始,后面的字符都不需要再读取了。在大多数UNIX和Linux系统中,在一行开始处按下Ctrl+D会传输文件结尾信号。Windows系统把一行开始处的Ctrl+Z识别为文件结尾信号。*/if (ch == '{' || ch == '[' || ch == '(') {/*如果是左括号,则压栈*/Push(&S, ch);}if (ch == '}') {if(GetTop(S, &e) && e == '{')/*如果栈里面有元素并且栈顶元素是 { ,弹出 { */Pop(&S, &e);}else Is_Match = false;}if (ch == ']') {if(GetTop(S, &e) && e == '[')/*如果栈里面有元素并且栈顶元素是 [ ,弹出 [ */Pop(&S, &e);}else Is_Match = false;}if (ch == ')') {if(GetTop(S, &e) && e == '(')/*如果栈里面有元素并且栈顶元素是 ( ,弹出 ( */Pop(&S, &e);}else Is_Match = false;}   }//while/*while 循环结束表示文本输入结束或者括号失配了,括号匹配的话,栈里面一定没有元素并且Is_Match == true*/if (Is_Empty && Is_Match) {printf("你所输入的文本括号匹配!");}else {printf("你所输入的文本括号不匹配!");}
}/*初始化栈函数的实现*/
Status InitStack(SqStack *S)
{S->base = (SElemType *)malloc(INIT_SIZE * sizeof(SElemType));if (!S->base) exit(OVERFLOW);S->top = S->base;S->stacksize = INIT_SIZE;return OK;
}/*判断栈是否为空的函数*/
bool Is_Empty(SqStack S)
{if (S.top == S.base) return true;else return false;
}/*取栈顶元素函数的实现*/
Status GetTop(SqStack S, SElemType *e)
{if (S.top == S.base) return ERROR;/*栈空*/*e = *(S.top - 1);return OK;
}/*压栈函数的实现*/
Status Push(SqStack *S, SElemType e)
{/*如果栈满*/if (S->top - S->base == S->stacksize) {/*这里涉及指针相减,在连续空间上,指针相减得到存储单元的个数,是int型,有疑问的翻下书再复习一下指针部分*/  SElemType *new_base;new_base = (SElemType *)realloc(S->base, (S->stacksize + INCREMENT) * sizeof(SElemType));if(!newbase) exit(OVERFLOW);/*将栈底和栈顶指针移到新动到的存储空间来*/S->base = new_base;S->top = S->base + S->stacksize;S->stacksize += INCREMENT;}*S->top++ = e;return OK;
}/*弹栈函数的实现*/
Status Pop(SqStack *S, SElemType *e)
{if (S->top == S->base) return ERROR;*e = *--S->top;return OK;
}

运行结果展示如下,在Win 10环境下,IDE用的是Dev C++,因为自己的电脑暂时没带,就凑合使用以下无需配置操作简单的Dev C++做演示
括号匹配:

括号不匹配:

好了,接下来进入正题:

由于顺序栈的初始空间空间固定大小,在元素满了之后需要重新申请空间,在元素很少时又有很多空间的浪费,链栈可以解决这个问题。
链栈是指用链式存储结构实现的栈,通常用单链表表示。

下面是链栈的C语言描述

typedef struct SNode {SElemType data;struct SNode *next;
}SNode, *LinkStack;

老规矩,将LinkStack作为栈顶指针,其他结点指针用SNode *加以区分
1.栈的初始化

/*因为栈的插入删除操作只在栈顶进行,栈不需要设头结点*/
Status InitStack(LinkStack *S)
{S = NULL;return OK;
}

2.入栈

/*动态申请节点空间,所以没有栈满一说*/
Status Push(LinkStack *S, SElemType e)
{SNode *p;p = (SNode *)malloc(sizeof(SNode));if (!p) exit(OVERFLOW);/*插入节点,让e成为新的栈顶元素*/p->data = e;p->next = *S;*S = p;return OK;
}

3.出栈

Status Pop(LinkStack *S, SElemType *e)
{SNode *p;if (*S == NULL) return ERROR;/*栈空*/*e = (*S)->data;/*让p指向栈顶元素空间,以备释放*/p = *S;*S = (*S)->next;free(p);return OK;
}

4.取栈顶元素

Status GetTop(LinkStack S, SElemType *e)
{if (S = NULL) return ERROR;*e = S->data;return OK;
}

剩下的一些比如清空、销毁栈、遍历栈里面的元素和链表的操作几乎一样,自己实现就可以了

那接下来说一下栈的应用:其实我们写的程序中的函数调用就是栈的逻辑,将连续调用(这个词不准确,但一时不知道用什么词,就是a调用b,b又调用c,c又…)的函数依次压栈,直到最后一个被调用的函数入栈,再依次出栈。函数的返回过程和调用过程相反,正好与栈的特性吻合。

一个很常用的例子就是递归函数了,函数通过不停地调用自身,直到到达递归基,就是递归结束的条件满足,函数开始依次返回。

比如有趣的汉诺塔传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针。印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔。不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片:一次只移动一片,不管在哪根针上,小片必须在大片上面。僧侣们预言,当所有的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而梵塔、庙宇和众生也都将同归于尽。

那我们如果累了,想毁灭宇宙,就得会解决这道问题吧。

假设是要将金片从A柱子移动到C柱子上,要保证最大的一片在最下面,那肯定另外63片先借助C柱子放到B柱子上(63片的Hanoi问题)
然后将A柱子上剩下的最大的一片搬到C柱子上去。
再将B柱子上上面的63片借助A移动到C柱子上去,那不是又和最开始A需要借助B把64片金片放到C上的问题一样的吗(63片的Hanoi问题)

自己先尝试写下代码解决这个问题,没思路再参考下面的。

代码实现如下:

#include <stdio.h>int count = 0; /*全局变量计步骤*//*函数声明*/
void Hanoi(char x, char y, char z, int n);
void move(int i, char a, char b);int main(void)
{int n = 64;/*呃,移动64片步骤太多,可以先设置个移动20片,看看要多少步*/Hanoi('A', 'B', 'C', n);return 0;
}/*搬金片动作的实现*/
void move(int i, char a, char b)
{printf("%d: 搬第%d片, %c->%c\n", ++count, i, a, b);
}/*汉诺塔问题的递归解决方法*/
void Hanoi(char x, char y, char z, int n)
{if (n == 1) move(1, x, z);else {Hanoi(x, z, y, n - 1);move(n, x, z);Hanoi(y, x, z, n - 1);}
}


上面的运行结果是n = 20的,我天价2000多的电脑运行了10分钟才得到的结果,需要1048575步。
由数学推导易知 n 片金片需要搬动 2^n - 1 次,那么搬完64片,需要 2^64 - 1 步,反正我的电脑是得不到结果了。
需要 18,446,744,073,709,551,615 步!假设搬动一片需要 2 秒,那么昼夜不停完成移动需要427,007,964,669,203天!需要1,169,884,834,710年!

科学家分析地球已经诞生了46亿年,还将存在50亿年,而汉诺塔问题的金片搬完要1169亿年,那还真是搬完地球都没了。

好了,下一章将开始队列的学习!

数据结构与算法学习笔记——链栈相关推荐

  1. 数据结构与算法学习笔记之先进先出的队列

    前言 队列是一种非常实用的数据结构,类似于生活中发排队,可应用于生活,开发中各个方面,比如共享打印机(先请求先打印),消息队列.你想知道他们是怎么工作的么.那就来一起学习一下队列吧 正文 一.队列的定 ...

  2. 数据结构与算法学习笔记之 从0编号的数组

    数据结构与算法学习笔记之 从0编号的数组 前言 数组看似简单,但掌握精髓的却没有多少:他既是编程语言中的数据类型,又是最基础的数据结构: 一个小问题: 为什么数据要从0开始编号,而不是 从1开始呢? ...

  3. 数据结构与算法学习笔记之 提高读取性能的链表(上)

    数据结构与算法学习笔记之 提高读取性能的链表(上) 前言 链表(Linked list)比数组稍微复杂一点,在我们生活中用到最常见的应该是缓存,它是一种提高数据读取性能的技术,常见的如cpu缓存,浏览 ...

  4. 数据结构与算法学习笔记4:递归+分治法

    数据结构与算法学习笔记4 递归 斐波那契数列 青蛙跳台阶问题 链表倒序打印 分治法 二分查找/折半查找 Binary Search 题目1:快速幂 题目2:如何判断一个数是否为2的次幂 递归 指在函数 ...

  5. 数据结构与算法 学习笔记(5):字符串

    数据结构与算法 学习笔记(5)- 字符串 本次笔记记录了LeetCode中关于字符串的一些问题,并给出了相应的思路说明和代码.题目编号与LeetCode对应,方便查找. 题目1:LeetCode 13 ...

  6. 数据结构与算法学习笔记——图 C++实现

    数据结构与算法学习笔记--图 C++实现 1 概念 2 图的表示方法 3 算法 3.1 拓扑排序 3.2 图的搜索算法 3.2.1 广度优先搜索(BFS) 3.2.2 深度优先搜索(DFS) 3.3 ...

  7. 数据结构与算法学习笔记15:最大流问题 / 二分图 / 有权无权二分图的匹配 / 匈牙利算法 / 银行家算法 / 稳定婚配

    数据结构与算法学习笔记15:最大流问题 / 二分图 / 有权无权二分图的匹配 / 匈牙利算法 / 银行家算法 / 稳定婚配 引入小题:最短路径 最大流问题(maximum flow problem) ...

  8. 数据结构与算法 学习笔记(8):字典、集合、哈希表

    数据结构与算法 学习笔记(8):字典.集合.哈希表 本次文章记录的是和字典.集合.哈希表等数据结构相关的LeetCode算法题(题号与LeetCode对应),包括其构造和使用,针对每一题或一类题给出了 ...

  9. 【数据结构与算法学习笔记】

    文章目录 前言 0 Preview与算法复杂度分析简述 1 线性数据结构 1.1 Stack 1.2 Queue 1.3 Deque 1.4 UnorderedList 1.5 OrderedList ...

最新文章

  1. 给网站添加icon图标
  2. 使用ML.NET + Azure DevOps + Azure Container Instances打造机器学习生产化
  3. Quartz快速入门
  4. 【小白学习C++ 教程】五、C++数据结构向量和数组
  5. Ubuntu 16.04上搭建CDH5.16.1集群
  6. Apollo进阶课程⑰丨Apollo感知之旅——传感器选择和安装
  7. 如何控制if跳出_Wasm介绍之5:控制指令 | 火星技术帖
  8. MIT6.830 lab4 SimpleDB Transactions 实验报告
  9. 交警高德强联手 助威吉林马拉松
  10. oracle中算百分比,Oracle百分比分析函数RATIO_TO_REPORT() OVER()实例详解
  11. 硬件设计1:常用元器件的选型理论依据
  12. 高手支招:免费拥有QQ魔法表情(转)
  13. windows2003中了一键还原7.9的招了
  14. 为什么iPhone 12 中国版不支持5G毫米波?
  15. Hive有分区文件到时select不到数据问题-----修复分区命令 msck repair table xxxxx
  16. 分享72个商务商城PHP源码,总有一款适合你
  17. 【理科】2020年高考数学(第三章导数)考点与题型全归纳
  18. 自定义鼠标滑过标签的title属性的样式
  19. Cross Stage Partial Network(CSPNet)
  20. 计算机病毒危害性分析,计算机病毒危害评析(共2220字).doc

热门文章

  1. 推荐 6 个本月 yyds 的开源项目
  2. 网口灯电路——反相器
  3. html5文字跳动特效,jQuery网页文字跳动动画特效
  4. 解决OBS录屏软件窗口采集不全的问题
  5. Atitit 算法之道 attilax著 1. 编码算法 3 1.1. Base64 htmlencode urlencode 3 2. Ui方面的算法 3 2.1. 软键盘算法 计算软键盘上下
  6. php-fpm 重启失败,php-fpm启动失败
  7. 游戏设计模式阅读笔记19——优化模式(空间分区)
  8. C语言基础ask‖码一些知识
  9. C语言拆分一个三位数。以及交换两个数(常规法复习加指针法学习)
  10. 2022年12月编程语言排行榜公布!