数据结构笔记#栈

可以说线性表的一个具体应用就是栈,可能看完以下代码你觉得这是什么嘛有什么卵用啊,但是栈在现实生活的中的应用,或者说这种概念的应用是非常广泛的。

比如说各种浏览器的返回上一级功能。

栈与线性表最大的差别就是它对数据的操控是受限的,遵守Last in First out(LIFO)“后进先出原则”的数据结构都可以叫栈。

栈一般长这个样子(美工欠下了3.5个亿带着他的小姨子跑了!)

右边是我们对线性表之单链表的正常理解,数据从表头到表尾依次排放。

左边是栈的特性,处于上层的元素(较新)叫top,处于底部的元素(最先放进去的那个)叫bottom。

这里注意一下top指针指向的位置,是一个空白的位置,而不是最顶层的那个数据。

而bottom指针则一直指向最底层的那个数据。

对栈的常见操作有push(入栈,将数据放入栈)和pop(出栈,将数据提取出来)。

这两个操作只能影响最顶层的元素。

以下是我的具体的代码实现,实现的方式有很多种,以下仅供参考。

Github

首先是栈的头文件.h

Stack.h

声明一下结构体及函数。

链表一样,栈你可以搞成链式也可以搞成顺序的,这里我用了顺序存储结构,方便操作。

 1 #ifndef _STACK_H_
 2 #define _STACK_H_
 3
 4 #include<stdio.h>
 5 #include<stdlib.h>
 6
 7 //以下两个数据大小视实际情况而定
 8 //初始栈容量
 9 #define STACK_INIT_SIZE 10
10 //每次扩容的增量
11 #define STACKINCREMENT 10
12
13 typedef int DataType;
14
15 struct stack
16 {
17     //指向栈最顶上的元素的接下来一个位置
18     //表示新入栈的值可以放在指向的地方
19     DataType *Top;
20     //指向栈底部,最里面的元素
21     DataType *Bottom;
22     //表示了当前栈的容量
23     int stacksize;
24 };
25 typedef struct stack STACK;
26
27 //新建栈
28 int InitStack(STACK *S);
29
30 //销毁栈
31 int DestroyStack(STACK *S);
32
33 //获取栈长度
34 int StackLength(STACK S);
35
36 //获取栈顶部元素
37 int GetTop(STACK S, DataType *e);
38
39 //Push操作,入栈,压栈
40 int Push(STACK *S, DataType e);
41
42 //Pop操作,出栈
43 int Pop(STACK *S, DataType *e);
44
45 //打印整表
46 int StackTraverse(STACK S);
47
48 #endif

Stack.c

不知道为什么感觉栈的代码比链表的简单。。。直接都贴上来吧。

首先是初始化链表和销毁链表。

 1 int InitStack(STACK *S)
 2 {
 3     //创建出设定长度的顺序表,地址赋给bottom指针
 4     S->Bottom = (DataType*)malloc(STACK_INIT_SIZE*sizeof(DataType));
 5     if (!S->Bottom)
 6     {
 7         return 0;
 8     }
 9     S->stacksize = STACK_INIT_SIZE;
10     S->Top = S->Bottom;
11     return 1;
12 }
13
14 int DestroyStack(STACK *S)
15 {
16     S->Top = NULL;
17     free(S->Bottom);
18     S->Bottom = NULL;
19     return 1;
20 }

然后是Push和Pop的函数,注释应该把代码解释的比较清楚了

 1 int Push(STACK *S, DataType e)
 2 {
 3     //当超出当前栈的容量时进行扩容
 4     //这里应该只有等于的情况
 5     //而不会大于
 6     if ((S->Top - S->Bottom) >= S->stacksize)
 7     {
 8         //realloc函数将开辟指定大小的储存空间
 9         //并将原来的数据全部移到这个新的储存空间
10         S->Bottom = (DataType*)realloc(S->Bottom, (S->stacksize + STACKINCREMENT)*sizeof(DataType));
11         if (!S->Bottom)
12         {
13             return 0;
14         }
15         //由于重新开辟了空间
16         //需要重新根据bottom指针的位置指定top
17         S->Top = S->Bottom + S->stacksize;
18         //最后增加当前栈容量
19         S->stacksize += STACKINCREMENT;
20     }
21     //再把入栈的数据存放好
22     *(S->Top++) = e;
23     return 1;
24 }
25
26 int Pop(STACK *S, DataType *e)
27 {
28     if (S->Bottom == S->Top)
29     {
30         printf("Empty Stack!Can not pop!\n");
31         return 0;
32     }
33     //top指针先减1再取值
34     *e = *(--S->Top);
35     return 1;
36 }

然后是其他一些奇奇怪怪的“辅助”函数

 1 int StackLength(STACK S)
 2 {
 3     return  S.Top - S.Bottom;
 4 }
 5
 6 int GetTop(STACK S, DataType *e)
 7 {
 8     if (S.Bottom != S.Top)
 9     {
10         //由于top指向的是最顶上元素的下一个位置
11         //所以取出最顶上元素的时候
12         //要把top减去1
13         *e = *(S.Top - 1);
14         return 1;
15     }
16     return 0;
17 }

最后是打印整个栈的数据的函数

 1 int StackTraverse(STACK S)
 2 {
 3     int timer = 0;
 4     int *cur=S.Bottom;
 5     if (S.Bottom ==S.Top)
 6     {
 7         printf("Empty!\n");
 8         return 1;
 9     }
10     while (cur < S.Top)
11     {
12         printf("%d) ", timer++);
13         printf("%d\n", *(cur++));
14     }
15     return 1;
16 }

最后随便写个main函数测试一下

Stacktest.c

 1 #include"Stack.h"
 2
 3 int main()
 4 {
 5     STACK s;
 6     int input=0;
 7     int output = 0;
 8
 9     InitStack(&s);
10     StackTraverse(s);
11
12     while(scanf("%d",&input) && input!=999)
13     {
14         Push(&s, input);
15     }
16     StackTraverse(s);
17     printf("Length: %d\n", StackLength(s));;
18
19     if (Pop(&s, &output))
20     {
21         printf("Poped : %d\n", output);
22     }
23
24     DestroyStack(&s);
25     return 0;
26 }

Stacktest.c

不同人的代码差别是很大的。。。但数据结构代码又没有一个标准,适和自己的需求就好,我也不敢确定我这么写最好。

如果感兴趣的话可以用栈做一个简单的计算器程序,用于计算比如

(3+(3-2))*10 = ?

这种的复合计算。

具体实现方法,我还没做呢。。。

时间: 2024-08-03 10:17:52

数据结构笔记#栈的相关文章

数据结构笔记——栈

栈的应用及构造 栈的简介 栈是一种只能从一端进行删除和插入的线性结构.因此栈具有后进先出的特点.例如进栈顺序是12345,如果5是第一个出栈的数字,则接下来出栈的一定是4,3,2,1.由于栈后进先出的特点,所以栈经常被递归算法调用,此时栈被称为递归工作栈.从栈的容量来看,栈可被分为动态栈可静态栈.动态栈顾名思义即使栈的容量可变,静态栈即是栈的容量是固定的. 用顺序表构造的静态栈及其操作 1.栈的构造:申请给定大小空间,将栈顶指针指向栈底. 2.栈的初始化:将栈的栈顶指针指向栈底. 3.栈的插入:

天勤考研数据结构笔记--栈的C语言实现

1.栈的基本概念 栈的定义:栈是一种只能在一端进行插入或删除操作的线性表.其中允许进行插入或删除的一端称为栈顶(top).栈顶是由一个称为栈顶指针的位置指示器(其实就是一个变量,对于顺序栈,就是数组索引,对于链式栈,就是节点地址的指针)来指示.栈的插入和删除操作一般称为入栈和出栈. 栈的特点:先进后出(FILO). 2.栈的本质 栈依照存储结构可分为顺序栈和链式栈.由栈的定义可知,栈是一种在操作上稍加限制的线性表,即栈的本质是线性表,而线性表恰好有两种主要的存储结构--顺序表和链表. 3.顺序栈

数据结构笔记之——括号匹配(栈的应用之一)(SDOJ 2134)

//  度过了上周的悲催状态,我决定好好学习了-- //书上括号匹配是栈的简单应用,正好在SDOJ上看到这道题,顺便做了下 题目地址:SDOJ 2134 数据结构实验之栈四:括号匹配 Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 给你一串字符,不超过50个字符,可能包括括号.数字.字母.标点符号.空格,你的任务是检查这一串字符中的( ) ,[ ],{ }是否匹配. 输入 输入数据有多组,处理到文件结束. 输出 如果匹配就输出

15、蛤蟆的数据结构笔记之十五栈的应用之栈与递归之八皇后问题

15.蛤蟆的数据结构笔记之十五栈的应用之栈与递归之八皇后问题 本篇名言:"人的一生应当这样度过:当回忆往事的时候,他不致于因为虚度年华而痛悔,也不致于因为过去的碌碌无为而羞愧:在临死的时候,他能够说:"我的整个生命和全部精力,都已经献给世界上最壮丽的事业--为人类的解放而斗争." 继续递归问题,本次是经典的八皇后问题: 欢迎转载,转载请标明出处: 1.  八皇后问题 八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例.该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出

14、蛤蟆的数据结构笔记之十四栈的应用之栈与递归之阿克曼函数

14.蛤蟆的数据结构笔记之十四栈的应用之栈与递归之阿克曼函数 本篇名言:"今天就是生命 ----- 是唯一你能确知的生命." 继续递归应用,阿克曼函数. 欢迎转载,转载请标明出处: 1.  阿克曼函数 阿克曼函数(Ackermann)是非原始递归函数的例子.它需要两个自然数作为输入值,输出一个自然数.它的输出值增长速度非常高,仅是对于(4,3)的输出已大得不能准确计算. Ackermann函数定义如下: 若m=0,返回n+1. 若m>0且n=0,返回Ackermann(m-1,1

13、蛤蟆的数据结构笔记之十三栈的应用之栈与递归之斐波那契数列

13.蛤蟆的数据结构笔记之十三栈的应用之栈与递归之斐波那契数列 本篇名言:"人生不是一支短短的蜡烛,而是一支由我们暂时拿着的火炬,我们一定要把它燃得." 继续递归的斐波那契数列问题. 欢迎转载,转载请标明出处: 1.  斐波那契数列 斐波那契数列,又称黄金分割数列,指的是这样一个数列:0.1.1.2.3.5.8.13.21.--在数学上,斐波纳契数列以如下被以递归的方法定义:F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2)(n≥2,n∈N*)在现代物理.准晶体结构.化学

7、蛤蟆的数据结构笔记之七栈的应用之数制转换

7.蛤蟆的数据结构笔记之七栈的应用之数制转换 本篇名言:"人生意义的大小,不在乎外界的变迁,而在乎内心的经验." 上面两篇中我们实现了链栈和链队列,接下去哦我们看看实际中栈的应用场景.本次来看下栈在数制转换的作用. 欢迎转载,转载请标明出处: 1.  原理介绍 十进制N和其他进制数的转换时计算机实现计算的基本问题.简单算法如下: N=(N div d )x d + N modd 2.  实现 2.1         定义结构体 定义堆栈的结构体 typedef struct { int

16、蛤蟆的数据结构笔记之十六栈的应用之栈与递归之汉诺塔问题

16.蛤蟆的数据结构笔记之十六栈的应用之栈与递归之汉诺塔问题 本篇名言:"人生的价值,并不是用时间,而是用深度去衡量的." 继续栈与递归应用,汉诺塔问题. 欢迎转载,转载请标明出处: 1.  汉诺塔问题 汉诺塔:汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具.大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘.大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上.并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一

11、蛤蟆的数据结构笔记之十一栈的应用之表达式求值实现

11.蛤蟆的数据结构笔记之十一栈的应用之表达式求值实现 本篇名言:"人生不售来回票,一旦动身,绝不能复返." 继续栈应用实现,这次是来看下表达式求值的栈实现. 欢迎转载,转载请标明出处: 1.  表达式求值 表达式求值是设计语言编译中的一个基本问题,它的实现是栈应用的又一个典型例子. 任何一个表达式都是由操作数(Operand).运算符(operator)和界限符(delimiter)组成. 操作数可以是常数也可以是变量或变量的标识符. 运算符可以分为算术运算符.关系运算符和逻辑运算符