数据结构-栈

定义

栈(Stack):只允许在一端进行插入或删除操作的线性表。首先栈是一种特殊的线性表,但是限定这种线性表只能在某一端进行插入和删除操作,如图3-1所示。

栈顶(top):线性表允许进行插入和删除的那一端。

栈底(bottom):固定的,不允许进行插入和删除的另一端。

空栈:不含任何元素的空表。

逻辑结构

添加元素只能在尾节点后添加,删除元素只能删除尾节点,查看节点也只能查看尾节点。

形象的说,栈是一个先进后出(LIFO)表,先进去的节点要等到后边进去的节点出来才能出来。

存储结构

栈的存储方式有:

  1. 顺序栈
  2. 链栈

顺序栈

栈的顺序存储称为顺序栈,它是利用一组地址连续的存储单元存放自栈底到栈顶的数据 元素,同时附设一个指针(top)指示当前栈顶的位置。

栈的顺序存储类型可描述为:

1 #define MaxSize 50  //定义栈中元素的最大个数
2 typedef struct{
3     Elemtype data[MaxSize];  //存放找中元素
4     int top;  // 栈顶指针
5 }SqStack;

栈顶指针:S.top,初始时设置S.top=-1;栈顶元素:S.data[S.top]。

进栈操作:栈不满时,栈顶指针先加1,再送值到栈顶元素。

出栈操作:栈非空时,先取栈顶元素值,再将栈顶指针减1。

栈空条件:S.top=-1;栈满条件:S.top==MaxSize-1;栈长:S.top+1。

由于顺序栈的入栈操作受数组上界的约束,当对栈的最大使用空间估计不足时,有可能 发生栈上溢,此时应及时向用户报告消息,以便及时处理,避免出错

注意:这里栈顶指针指向的就是栈顶元素,所以进栈时的操作是S.data[++S.top]=x,出 栈时的操作是x=S.data[S.top--]。如果栈顶指针初始化为S.top=0,即栈顶指针指向栈顶元素 的下一个位置,则入栈操作变为S.data[S.top++]=x,出栈操作变为x=S.data[--S.top]。相应的 栈空、栈满条件也会发生变化。请读者仔细体会其中的不同之处,做题时也应灵活应变。、

共享栈(共享顺序栈)

利用栈底位置相对不变的特性,可以让两个顺序栈共享一个一维数据空间,将两个栈的 栈底分别设置在共享空间的两端,两个栈顶向共享空间的中间延伸,如图3-3所示。


图3-3  两个顺序栈共享存储空间

两个栈的栈顶指针都指向栈顶元素,top0=-1 时0号桟为空,top1=MaxSize时1号栈为 空;仅当两个栈顶指针相邻(top1-top0=1) 时,判断为栈满。当0号栈进栈时top0先加1 再赋值,1号栈进栈时top1先减1再赋值;出栈时则刚好相反。

共享栈是为了更有效地利用存储空间,两个栈的空间相互调节,只有在整个存储空间被 占满时才发生上溢。其存取数据的时间复杂度均为0(1),所以对存取效率没有什么影响。

链栈

釆用链式存储的栈称为链栈,链栈的优点是便于多个栈共享存储空间和提高其效率,且 不存在栈满上溢的情况。通常釆用单链表实现,并规定所有操作都是在单链表的表头进行的。 这里规定链栈没有头结点,Lhead指向栈顶元素,如图3-4所示。


图3-4  栈的链式存储

栈的链式存储类型可描述为

1 typedef struct Linknode{
2     ElemType data;  //数据域
3     struct Linknode *next;  //指针域
4 } *LiStack;  //栈类型定义

釆用链式存储,便于结点的插入与删除。链栈的操作与链表类似,

操作运算

栈的应用

使用栈的时候一般不用自己重新去写,因为STL给我们实现了一个很安全的栈,可以放心去使用。也可以用数组模拟一个,很简单。

编译器调用函数就用了栈结构,当第一个函数还没执行完毕,调用第二个函数的时候,编译器就会把第一个函数压栈,第二个函数调用完毕的时候,就会取栈顶函数,也就是第一个函数继续执行。

实现递归的工作原理

汇编程序设计和高级语言程序设计调用函数和被调用函数之间的链接和信息转换都是通过栈来实现的。

在一个函数中调用另一个函数时,系统需要做三件事:

  1. 将需要传递给被调用函数的实参和函数返回地址传递给被调用函数保存;
  2. 为被调用函数的局部变量分配存储区;
  3. 将控制转移移到被调用函数入口;

在调用完成后,系统需要完成三件事,结束相应的调用过程:

  1. 保存计算结果
  2. 释放局部变量存储区
  3. 根据被调用函数保存的返回地址返回到调用函数;

函数调用时利用栈的后进先出原则,每当函数调用时,系统分配一个存储区,并将该存储区压入栈顶。当函数调用完成时系统释放存储区,弹出栈顶元素。这个栈应该是程序的活动栈,在整个程序运行期中都有效。

递归函数和普通函数调用的区别是递归函数的调用函数被调用函数时同一个,所以在调用时系统需要为递归函数建立一个“递归工作栈”,作为整个递归函数运行时的数据存储区。每一层递归函数构成一条工作记录,工作记录的内容就是被调用函数的普通必须内容-返回地址+实参,另外多了局部变量。每进入一层递归函数就产生一条工作记录压入栈,每完成一层递归函数就弹出当前栈顶元素。正在运行的函数必须是栈顶的活动记录,被称为“活动记录”,并将指向当前活动记录的栈顶指针成为“当前环境指针”。

调用函数和被调用函数之间不一定只能传递值的引用,也可以传递地址,这取决与高级程序设计语言的设计。

参考链接:

http://c.biancheng.net/cpp/html/2699.html

http://www.cppblog.com/cxiaojia/archive/2012/08/01/185913.html

https://books.google.com.sg/books?id=H3ktn0sp5LsC&pg=PA44&dq=%E6%A0%88+%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84&hl=zh-CN&sa=X&ved=0ahUKEwiCtJ7N8vLOAhUKu48KHVrfBKcQ6AEIIjAB#v=onepage&q=%E6%A0%88%20%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84&f=false

时间: 2024-10-11 01:26:18

数据结构-栈的相关文章

南阳OJ-2 括号配对 (数据结构-栈的应用)

括号配对问题 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 现在,有一行括号序列,请你检查这行括号是否配对. 输入 第一行输入一个数N(0<N<=100),表示有N组测试数据.后面的N行输入多组输入数据,每组输入数据都是一个字符串S(S的长度小于10000,且S不是空串),测试数据组数少于5组.数据保证S中只含有"[","]","(",")"四种字符 输出 每组输入数据的输出占一行,

poj 2082 Terrible Sets (数据结构 ——栈 STL)

 Terrible Sets Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 2999   Accepted: 1549 Description Let N be the set of all natural numbers {0 , 1 , 2 , . . . }, and R be the set of all real numbers. wi, hi for i = 1 . . . n are some elem

数据结构——栈——寻找下一个较大元素

题目描述 给出一个数组,向右寻找每一个元素的下一个较大的元素,没有更大的则为-1 举例 {4,6,1,3,2,5} 则求得的答案应为 {6,-1,3,5,5,-1} 题目分析 首先对于这样的题目,我们总是先想到最简单的,那么就是枚举,每次循环一个元素,不停的向右找就可以了.时间复杂度应该是n^2 但是这样肯定是不够用的. 然后我们考虑,这道题我们实际上遇到的问题是什么? 其实简单的说,这道题的意思是,在变化的数组中找到下一个较大的值. 难点在于,数组元素的变化,以及不是找最大值,而是找下一个较大

C数据结构-栈和队列,括号匹配举例

1.栈和队列是两种特殊的线性表 运算操作被限定只能在表的一端或两端插入,删除元素,故也称它们为限定的线性表结构 2.栈的基本运算 1).Stackinit(&s) 构造一个空栈 2).Stackempty(s) 判断s是否为空栈,当s为空栈时,函数返回值1 否则 0 3).Push(&s,x)  在栈s 的顶部插入元素x,简称将x入 栈 4).Pop(&s,&x) 在栈s 中删除顶元并将其值保存在x单元中返回,简称将x出栈 5)Gettop(s,&x)  读s栈中的

数据结构-栈的压入、弹出序列

题目:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个顺序是否是该栈的弹出顺序.假设压入栈的所有数字均不相等.例如序列1,2,3,4,5是某栈的压栈序列,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但是4,3,5,1,2就不可能是. 分析:首先利用图像进行形象化的理解.可以发现其压入的顺序并不是所有的一次性压入.同时要考虑栈是否为空.以及其长度.这段代码写的很痛苦,继续训练. /* 剑指offer面试题22 */ #include <iostream> #include &

利用数据结构栈求解迷宫问题

本段程序主要利用数据结构栈的先进后出特点,实现回溯求解迷宫路径问题. #include<iostream> #include<stack> using namespace std; //坐标类 struct Point { int x; int y; }; //地图类 template<int A> struct Map { int (*p)[A]; int row;//行数 int col;//列数 }; //start起始点, end终止点 template<

数据结构 栈笔记

// 数据结构 栈的实现 C语言, 只能从头部储存和销毁数据 # include <stdio.h> # include <stdlib.h> # include <malloc.h> // 线性储存部分 typedef struct NONE { int data; struct NONE * pNext; }None, * pNone; // 栈的头部和底部 typedef struct stack { pNone top; pNone bottom; }St, *

大话数据结构----栈

栈的定义: 栈(stack)是限定尽在表尾进行插入和删除操作的线性表. 从定义中可以看出,栈也是线性表,是一个特殊的线性表,之前说线性的表的时候,线性表可以在任意位置进行插入插入,而栈比线性表特殊的地方的就是不能随意的插入和删除了,栈的插入和删除只能在规定的同一端进行,而被允许插入和删除的一端称为栈顶,另一端称为栈底. 从栈的特性中我们能发现:1).栈是一种后进先出的线性表,因为栈只有一个出入口,每次出栈是最后进的那个先出去,后一个才能出去,就像我们出电梯一样,里面的人被阻住,只有外面的人出去,

java数据结构栈

栈的原则是先进后出,比如一堆摞起来的书,后放上去的会被最先拿到. 栈的特点是每次只允许访问一个元素. 栈是一种抽象出来的数据结构,它的底层存储依赖于数组和链表,下面列出它的两种实现 public interface Stack <T>{ boolean isEmpty(); void clear(); int length(); boolean push(T obj); T pop(); boolean hashNext(); } public class ArrayStack<T>

数据结构-栈的实现之括号匹配检测

假设表达式中只允许两种括号:().{}:正确表达顺序为:()或{}或({})或{({}{})}的形势:如{(}或(})或({)}的表达形势均不对.算法的设计思想: 出现左括弧则进栈: 出现右括弧则首先检测栈是否为空, 若栈空则表明此右括弧多余,表达式不匹配. 否则和栈顶数据比较,若匹配则栈顶出栈. 否则表明表达式不匹配: 最后若栈空且没有做鱼右括弧则匹配正确,否则表明不匹配. 实现代码如下(Stack.h头文件为之前写的数据结构-栈的顺序结构中写的数组那个方法,用到了里面栈的结构和连个基本栈操作