数据结构学习笔记02堆栈

栈(stack)又名堆栈,它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。是一种后进先出(LIFO)的数据结构。

一.栈的顺序存储

如图,左图为空栈,右图为已存放数据的栈。不难发现,栈只有一个口子,数据只能从一端进行入栈(push)和出栈(pop)操作。数据data的入栈顺序为 0, 1, 2.因此,出栈顺序只能为2,  1,0,从栈顶向栈底依次取出。

  1 //顺序栈
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4
  5 typedef int Status;
  6 typedef int SElemType; /* SElemType类型根据实际情况而定,这里假设为int */
  7
  8 #define STACK_INTI_SIZE 100        //存储空间初始分配量
  9 #define STACKINCREMENT 10        //存储空间分配增量
 10
 11 #define OK 1
 12 #define ERROR 0
 13 #define INFEASIBLE -1
 14 #define OVERFLOW -2
 15
 16 typedef struct {
 17     SElemType *base;
 18     SElemType *top;        //栈顶指针
 19     int stacksize;        //当前已分配的存储空间
 20 }SqStack;
 21
 22 Status InitStack(SqStack &S);
 23 Status DestroyStack(SqStack &S);
 24 Status ClearStack(SqStack &S);
 25 bool StackEmpty(SqStack S);
 26 int StackLength(SqStack S);
 27 Status GetTop(SqStack S, SElemType &e);
 28 Status Push(SqStack &S, SElemType e);
 29 Status Pop(SqStack &S, SElemType &e);
 30 Status StackTraverse(SqStack S, Status(*visit)(SElemType e));
 31
 32 Status visit(SElemType c)
 33 {
 34     printf("%d ", c);
 35     return OK;
 36 }
 37 /*操作结果:构造一个空栈S*/
 38 Status InitStack(SqStack &S)
 39 {
 40     S.base = (SElemType *)malloc(STACK_INTI_SIZE * sizeof(SElemType));
 41     if (!S.base) exit(OVERFLOW);
 42     S.top = S.base;
 43     S.stacksize = STACK_INTI_SIZE;
 44     return OK;
 45 }
 46 /*初始条件:栈S已存在。
 47 操作结果:栈S被销毁*/
 48 Status DestroyStack(SqStack &S)
 49 {
 50     free(S.base);
 51     free(&S);
 52     S.top = NULL;
 53     S.base = NULL;
 54     S.stacksize = 0;
 55     return OK;
 56 }
 57 /*初始条件:栈S已存在。
 58 操作结果:将S清为空栈*/
 59 Status ClearStack(SqStack &S)
 60 {
 61     S.top = S.base;
 62     return OK;
 63 }
 64 /*初始条件:栈S已存在。
 65 操作结果:若栈S为空栈,则返回TRUE,否则FALSE*/
 66 bool StackEmpty(SqStack S)
 67 {
 68     if (S.top == S.base)
 69         return true;
 70     else
 71         return false;
 72 }
 73 /*初始条件:栈S已存在。
 74 操作结果:返回S的元素个数,即栈的长度*/
 75 int StackLength(SqStack S)
 76 {
 77     return (S.top - S.base);
 78 }
 79 /*初始条件:栈S已存在且非空。
 80 操作结果:用e返回S的栈顶元素*/
 81 Status GetTop(SqStack S, SElemType &e)
 82 {
 83     if (S.top == S.base) return ERROR;    //若栈空 返回ERROR
 84     e = *(S.top - 1);
 85     return OK;
 86 }
 87 /*初始条件:栈S已存在。
 88 操作结果:插入元素e为新的栈顶元素*/
 89 Status Push(SqStack &S, SElemType e)
 90 {
 91     if (S.top - S.base >= S.stacksize) {        //栈满追加存储空间
 92         S.base = (SElemType *)realloc(S.base,
 93                     (S.stacksize + STACKINCREMENT) * sizeof(SElemType));
 94         if (!S.base) exit(OVERFLOW);            //存储分配失败
 95         S.top = S.base + S.stacksize;/*realloc可能返回了新的地址,所以top的地址需重新确定。*/
 96         S.stacksize += STACKINCREMENT;            //更新stacksize的值
 97     }
 98     *S.top++ = e;  //*S.top = e; S.top++
 99     return OK;
100 }
101 /*初始条件:栈S已存在且非空。
102 操作结果:删除S的栈顶元素,并用e返回其值*/
103 Status Pop(SqStack &S, SElemType &e)
104 {
105     if (S.top == S.base) return ERROR;
106     e = * --S.top;  //S.top--; e = *S.top;
107     return OK;
108 }
109 /*初始条件:栈S已存在且非空。
110 操作结果:从栈底到栈顶依次对S的每个数据元素调用函数visit()。
111 一旦visit()失败,则操作失败。*/
112 Status StackTraverse(SqStack S, Status(*visit)(SElemType e))
113 {
114     if (S.base == S.top)
115     {
116         printf("栈为空!");
117         return ERROR;
118     }
119     for (SElemType *p = S.base;p < S.top;p++)
120         visit(*p);
121
122     printf("\n");
123     return OK;
124 }
125 int main()
126 {
127     SqStack s;
128     int e,length;
129
130     if (InitStack(s) == OK)
131         for (int j = 1;j <= 10;j++)
132             Push(s, j);
133     length = StackLength(s);
134     StackTraverse(s,visit);
135     printf("length = %d\n", length);
136     if (StackEmpty(s) == true)
137         printf("empty!\n");
138     else printf("not empty!\n");
139     Pop(s, e);
140     printf("e = %d\n", e);
141     ClearStack(s);
142     if (StackEmpty(s) == true)
143         printf("empty!\n");
144     else printf("not empty!\n");
145     DestroyStack(s);
146     if (StackEmpty(s) == true)
147         printf("empty!\n");
148     else printf("not empty!\n");
149     system("pause");
150     return 0;
151 }

sj2_0

栈的顺序存储表示:

#define STACK_INTI_SIZE 100            //存储空间初始分配量

#define STACKINCREMENT 10           //存储空间分配增量

typedef struct {

SElemType *base;        //在栈构造之前和销毁之后,base值为NULL

SElemType *top;          //栈顶指针

int stacksize;         //当前已分配的存储空间

}SqStack;

顺序栈的基本操作:/*只需浏览,作了解,详情(代码:sj2_0)*/

Status InitStack(SqStack &S);

操作结果:构造一个空栈S。

Status DestroyStack(SqStack &S);

初始条件:栈S已存在。

    操作结果:栈S被销毁。

Status ClearStack(SqStack &S);

初始条件:栈S已存在。

    操作结果:将S清为空栈

Status StackEmpty(SqStack S);

初始条件:栈S已存在。

    操作结果:若栈S为空栈,则返回TRUE,否则FALSE。

int StackLength(SqStack S);

初始条件:栈S已存在。

    操作结果:返回S的元素个数,即栈的长度。

Status GetTop(SqStack S, SElemType &e);

    初始条件:栈S已存在且非空。

    操作结果:用e返回S的栈顶元素。

Status Push(SqStack &S, SElemType e);

初始条件:栈S已存在。

    操作结果:插入元素e为新的栈顶元素。

Status Pop(SqStack &S, SElemType &e);

    初始条件:栈S已存在且非空。

    操作结果:删除S的栈顶元素,并用e返回其值。

Status StackTraverse(SqStack S, Status(*visit)(SElemType e));

初始条件:栈S已存在且非空。

    操作结果:从栈底到栈顶依次对S的每个数据元素调用函数visit()。

    一旦visit()失败,则操作失败。

1.入栈操作

  算法思路:

  1. *top = e

  2. top++

  3.若栈满用realloc追加空间

  //malloc、calloc、realloc的区别  http://www.cnblogs.com/kuotian/p/5277335.html

 1 /*初始条件:栈S已存在。
 2 操作结果:插入元素e为新的栈顶元素*/
 3 Status Push(SqStack &S, SElemType e)
 4 {
 5     if (S.top - S.base >= S.stacksize) {        //栈满追加存储空间
 6         S.base = (SElemType *)realloc(S.base,
 7                     (S.stacksize + STACKINCREMENT) * sizeof(SElemType));
 8         if (!S.base) exit(OVERFLOW);            //存储分配失败
 9         S.top = S.base + S.stacksize;/*realloc可能返回了新的地址,所以top的地址需重新确定。*/
10         S.stacksize += STACKINCREMENT;            //更新stacksize的值
11     }
12     *S.top++ = e;  //*S.top = e; S.top++
13     return OK;
14 }

2.出栈操作

  算法思路:

  1.若top == base 即栈为空,不能pop,返回ERROR。

  2.top—

  3.e = *top

1 /*初始条件:栈S已存在且非空。
2 操作结果:删除S的栈顶元素,并用e返回其值*/
3 Status Pop(SqStack &S, SElemType &e)
4 {
5     if (S.top == S.base)
6             return ERROR;
7     e = * --S.top;  //S.top--; e = *S.top;
8     return OK;
9 }        

practice:

1.假设以顺序存储结构实现一个双向栈,即在一维数组的存储空间中存在着两个栈,他们的栈底分别设在数组的两个端点。试编写实现这个双向栈tws的三个操作:初始化inistack(tws)、入栈push(tws,I,x)和出栈pop(tws,i)的算法,其中i为0或1,用以分别指示设在数组两端的两个栈,并讨论按过程(正/误状态变量可设为变参)或函数设计这些操作算法各有说明优缺点。(代码:sj2_1)

  1 /*顺序存储结构双向栈 */
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4
  5 typedef int Status;
  6 typedef int SElemType; /* SElemType类型根据实际情况而定,这里假设为int */
  7
  8 #define OK 1
  9 #define ERROR 0
 10 #define INFEASIBLE -1
 11 #define OVERFLOW -2
 12
 13 #define MAXSIZE 100
 14
 15 #define LEFT 1
 16 #define RIGHT 0
 17 typedef struct
 18 {
 19     SElemType data[MAXSIZE];
 20     int top1;    /* 栈1栈顶 */
 21     int top2;    /* 栈2栈顶 */
 22 }SqDoubleStack;
 23
 24 Status InitStack(SqDoubleStack &S);
 25 Status DestroyStack(SqDoubleStack &S);
 26 Status ClearStack(SqDoubleStack &S);
 27 bool StackEmpty(SqDoubleStack S);
 28 int StackLength(SqDoubleStack S, int flag);
 29 Status GetTop(SqDoubleStack S, SElemType &e,int flag);
 30 Status Push(SqDoubleStack &S, SElemType e, int flag);
 31 Status Pop(SqDoubleStack &S, SElemType &e, int flag);
 32 Status StackTraverse(SqDoubleStack S, Status(*visit)(SElemType e),int flag);
 33
 34 Status visit(SElemType c)
 35 {
 36     printf("%d ", c);
 37     return OK;
 38 }
 39
 40 Status InitStack(SqDoubleStack &S)
 41 {
 42     S.top1 = -1;
 43     S.top2 = MAXSIZE;
 44     return OK;
 45 }
 46
 47 Status DestroyStack(SqDoubleStack &S)
 48 {
 49     S.top1 = -1;
 50     S.top2 = -1;
 51 //    S.top1 = NULL;
 52 //    S.top2 = NULL;
 53     return OK;
 54 }
 55
 56 Status ClearStack(SqDoubleStack &S)
 57 {
 58     S.top1 = -1;
 59     S.top2 = MAXSIZE;
 60     return OK;
 61 }
 62
 63 bool StackEmpty(SqDoubleStack S)
 64 {
 65     if (S.top1 == -1 && S.top2 == MAXSIZE)
 66         return true;
 67     else
 68         return false;
 69 }
 70
 71 int StackLength(SqDoubleStack S, int flag)
 72 {
 73     if (flag == LEFT)
 74         return (S.top1 + 1);
 75     else
 76         return (MAXSIZE - S.top2);
 77 }
 78 Status GetTop(SqDoubleStack S, SElemType &e, int flag)
 79 {
 80     if (flag == LEFT)
 81         e = S.data[S.top1];
 82     else
 83         e = S.data[S.top2];
 84     return OK;
 85 }
 86
 87 Status Push(SqDoubleStack &S, SElemType e, int flag)
 88 {
 89     if (S.top1 + 1 == S.top2)
 90         return ERROR;
 91     if (flag == LEFT)
 92         S.data[++S.top1] = e;
 93     else
 94         S.data[--S.top2] = e;
 95     return OK;
 96 }
 97
 98 Status Pop(SqDoubleStack &S, SElemType &e, int flag)
 99 {
100     if (flag == LEFT) {
101         if (S.top1 == -1) return ERROR;
102         else
103             e = S.data[S.top1--];
104
105     }
106     else {
107         if (S.top2 == MAXSIZE) return ERROR;
108         else
109             e = S.data[S.top2++];
110     }
111     return OK;
112 }
113
114 Status StackTraverse(SqDoubleStack S, Status(*visit)(SElemType e),int flag)
115 {
116     int i;
117     if (flag == LEFT)
118     {
119         for (i = 0;i <= S.top1;i++)
120             visit(S.data[i]);
121     }
122     else
123     {
124         for (i = MAXSIZE - 1;i >= S.top2;i--)
125             visit(S.data[i]);
126     }
127     printf("\n");
128     return OK;
129 }
130
131 int main()
132 {
133     SqDoubleStack s;
134     int e;
135     InitStack(s);
136
137     Push(s, 2, 1);
138     Push(s, 7, 1);
139     Push(s, 3, 0);
140     Push(s, 5, 0);
141     Push(s, 5, 0);
142
143     StackTraverse(s, visit, 1);
144     StackTraverse(s, visit, 0);
145     system("pause");
146     return 0;
147 }

sj2_1

二.链栈

栈的链式表示如图,栈的操作是线性表操作的特例。(代码: sj2_2)

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3
 4 #define OK 1
 5 #define ERROR 0
 6
 7
 8 typedef int Status;
 9 typedef int ElementType; /* SElemType类型根据实际情况而定,这里假设为int */
10
11
12 struct SNode{
13     ElementType data;
14     struct SNode *next;
15 };
16 typedef struct SNode *PtrToSNode;//PtrToSNode指向结点的指针
17 typedef PtrToSNode Stack;//Stack指向结点的指针
18
19 Stack CreateStack();
20 bool IsEmpty(Stack S);
21 bool Push(Stack S, ElementType X);
22 ElementType Pop(Stack S);
23
24 /* 构建一个堆栈的头结点,返回该结点指针 */
25 Stack CreateStack()
26 {
27     Stack S;
28     S = (PtrToSNode)malloc(sizeof(struct SNode));
29     S->next = NULL;
30     return S;
31 }
32 /* 判断堆栈S是否为空,若是返回true;否则返回false */
33 bool IsEmpty(Stack S)
34 {
35     return ( S->next == NULL );
36 }
37
38 /* 将元素X压入堆栈S */
39 bool Push(Stack S, ElementType X)
40 {
41     PtrToSNode tmpCell;
42     tmpCell = (PtrToSNode)malloc(sizeof(struct SNode));
43     tmpCell->data = X;
44     tmpCell->next = S->next;
45     S->next = tmpCell;
46     return true;
47 }
48
49 /* 删除并返回堆栈S的栈顶元素 */
50 ElementType Pop(Stack S)
51 {
52     PtrToSNode firstCell;
53     ElementType topElem;
54     if( IsEmpty(S) ) {
55         printf("堆栈空");
56         return ERROR;
57     } else {
58         firstCell = S->next;
59         topElem = firstCell->data;
60         S->next = firstCell->next;
61         free(firstCell);
62         return topElem;
63     }
64 }
65 int main()
66 {
67     Stack S;
68     S = CreateStack();
69     if(IsEmpty(S))
70         printf("堆栈空\n");
71     else
72         printf("堆栈不空\n");
73     Push(S, 10);
74     if(IsEmpty(S))
75         printf("堆栈空\n");
76     else
77         printf("堆栈不空\n");
78     printf("pop = %d\n",Pop(S));
79     Pop(S);
80     return 0;
81 }

sj2_2

1.入栈操作

  算法思路:

  1. 新建一个结点tmpCell
  2. tmpCell->next = S->next  ①
  3. S->next = tmpCell        ②

 1 /* 将元素X压入堆栈S */
 2 bool Push(Stack S, ElementType X)
 3 {
 4     PtrToSNode tmpCell;
 5     tmpCell = (PtrToSNode)malloc(sizeof(struct SNode));
 6     tmpCell->data = X;
 7     tmpCell->next = S->next;
 8     S->next = tmpCell;
 9     return true;
10 }

2.出栈操作

  算法思路:

  1.判断堆栈是否为空,若为空,无法pop,返回 ERROR

  2.确定栈顶元素firstCell,将其data赋值给topElem    ①

  3.S->next = firstCell->next   ②

  4.free(firstCell)                 ③

 1 /* 删除并返回堆栈S的栈顶元素 */
 2 ElementType Pop(Stack S)
 3 {
 4     PtrToSNode firstCell;
 5     ElementType topElem;
 6     if( IsEmpty(S) ) {
 7         printf("堆栈空");
 8         return ERROR;
 9     } else {
10         firstCell = S->next;
11         topElem = firstCell->data;
12         S->next = firstCell->next;
13         free(firstCell);
14         return topElem;
15     }
16 }

三.堆栈的其他应用

1.函数调用及递归实现

2.深度优先搜索

3.回朔算法

4.……

时间: 2024-10-07 16:59:29

数据结构学习笔记02堆栈的相关文章

小猪的数据结构学习笔记(四)

小猪的数据结构学习笔记(四) 线性表之静态链表 --转载请注明出处:coder-pig 本章引言: 在二,三中中我们分别学习了顺序表中的线性表与单链表,线性表有点类似于 我们前面所学的数组,而单链表使用的最多的是指针,这里问个简单的问题, 如果是在以前没有指针的话,前辈先人们怎么实现单链表呢?大家思考下! 没有指针,那么用什么来代替呢?前辈先人们非常机智,想出了使用下标+游标的方式 来实现单链表的效果!也就是今天要讲的--静态链表! 当然你也可以直接跳过本章,因为有了单链表就没有必要用静态链表了

【OpenGL 学习笔记02】宽点画线

我们要知道,有三种绘图操作是最基本的:清除窗口,绘制几何图形,绘制光栅化对象. 光栅化对象后面再解释. 1.清除窗口 比如我们可以同时清除颜色缓冲区和深度缓冲区 glClearColor (0.0, 0.0, 0.0, 0.0);//指定颜色缓冲区清除为黑色 glClearDepth(1.0);//指定深度缓冲区的清除值为1.0 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//指定要清除的缓冲区并清除 2.绘制几何图形 先要设置绘制颜色,

小猪的数据结构学习笔记(二)

小猪的数据结构学习笔记(二) 线性表中的顺序表 本节引言: 在上个章节中,我们对数据结构与算法的相关概念进行了了解,知道数据结构的 逻辑结构与物理结构的区别,算法的特性以及设计要求;还学了如何去衡量一个算法 的好坏,以及时间复杂度的计算!在本节中我们将接触第一个数据结构--线性表; 而线性表有两种表现形式,分别是顺序表和链表;学好这一章很重要,是学习后面的基石; 这一节我们会重点学习下顺序表,在这里给大家一个忠告,学编程切忌眼高手低,看懂不代表自己 写得出来,给出的实现代码,自己要理解思路,自己

SWIFT学习笔记02

1.//下面的这些浮点字面量都等于十进制的12.1875: let decimalDouble = 12.1875 let exponentDouble = 1.21875e1 let hexadecimalDouble = 0xC.3p0//==12+3*(1/16) 2.//类型别名,用typealias关键字来定义类型别名 typealias AudioSample = UInt16 var maxAmplitudeFound = AudioSample.min 3.//元组 let ht

Blender学习笔记 | 02 | 操作

Shift 点击不同图层 同时显示多图层物件 z 切换 Solid / Wireframe 视图模式 点选物件后M 移动到图层选项 Ctrl + 鼠标左键拖动 自由全选物件 B 方形区域圈选物件 Tab Object / Edit Mode 切换 T 开 / 关 侧栏 Ctrl + Tab 编辑状态下切换编辑对象 E Extrude Region 推挤区域.以发现为轴线. X 删除物件菜单 Blender学习笔记 | 02 | 操作,布布扣,bubuko.com

mongodb 学习笔记 02 -- CURD操作

mongodb 学习笔记 02 – CURD操作 CURD代表创建(Create).更新(Update).读取(Read)和删除(Delete)操作 创建库 直接 use 库名 然后创建collection 就可以创建库 创建collecion db.createCollection("collectionName") 隐式创建collection db.collectionName.insert({xxxxxx}) 删除collection db.collectionName.dro

软件测试之loadrunner学习笔记-02集合点

loadrunner学习笔记-02集合点 集合点函数可以帮助我们生成有效可控的并发操作.虽然在Controller中多用户负载的Vuser是一起开始运行脚本的,但是由于计算机的串行处理机制,脚本的运行随着时间的推移,并不能完全达到同步.这个时候需要手工的方式让用户在同一时间点上进行操作来测试系统并发处理的能力,而集合点函数就能实现这个功能. 可通过将集合点插入到 Vuser 脚本来指定会合位置.在 Vuser 执行脚本并遇到集合点时,脚本将暂停执行,Vuser 将等待 Controller 或控

Wojilu学习笔记 (02)

使用RequireJS (1)整个页面,应该只有一个 <script src="" > 标签,并且放在页面底部,用来引入 RequireJS 和 main.js 文件 <script data-main="~js/main" src="~js/lib/require-jquery-wojilu.js?v=#{jsVersion}"></script> (2)在页面头部的 <head> 部分,增加一行

小猪的数据结构学习笔记(五)

小猪的数据结构学习笔记(五) 线性表之--循环链表                           --转载请注明出处:coder-pig 循环链表知识点归纳: 相关代码实现: ①判断是否为空表: ②单循环链表的存储结构 其实和单链表的结构是一样的! /*定义循环链表的存储结构*/ typedef struct Cir_List { int data; struct Cir_List *next; }Lnode; ③初始化循环单链表 代码如下: //1.循环链表的初始化 //表示一个元素,如