栈,线性表的一种特殊的存储结构。与学习过的线性表的不同之处在于栈只能从表的固定一端对数据进行插入和删除操作,另一端是封死的。

图1 栈结构示意图
由于栈只有一边开口存取数据,称开口的那一端为“栈顶”,封死的那一端为“栈底”(类似于盛水的木桶,从哪进去的最后还得从哪出来)。

栈的“先进后出”原则

使用栈存储数据元素,对数据元素的“存”和“取”有严格的规定:数据按一定的顺序存储到栈中,当需要调取栈中某数据元素时,需要将在该数据元素之后进栈的先出栈,该数据元素才能从栈中提取出来。

如图 1 ,栈中存放了 4 个数据元素,进栈的顺序是 A 先进栈,然后 B 进,然后 C 进,最后 D 进栈;当需要调取 A 时,首先 D 出栈,然后 C 出栈,然后 B 出栈,最后 A 才能出栈被调用。

就好比只有一个门的车库(每次仅允许一辆车通过),每辆车好比一个数据元素,只有离门最近的车先开出来,里边的车才能出来;最里边的车是最先开进去的,注定要最后出来。

栈操作数据元素的方法

栈操作数据元素只有两种动作:

  1. 数据元素用栈的数据结构存储起来,称为“入栈”,也叫“压栈”。
  2. 数据元素由于某种原因需要从栈结构中提取出来,称为“出栈”,也叫“弹栈”。

栈的两种表示方式

既然栈也是线性表,那么它就同样有线性表的两种表示形式:顺序栈 和 链式栈(简称“链栈”)。

两者的区别在于存储的数据元素在物理结构上是否是相互紧挨着的。顺序栈存储元素预先申请连续的存储单元;链栈需要即申请,数据元素不紧挨着。

栈的“上溢”和“下溢”

栈存储结构调取栈中数据元素时,要避免出现“上溢”和“下溢”的情况:

“上溢”:在栈已经存满数据元素的情况下,如果继续向栈内存入数据,栈存储就会出错。

“下溢”:在栈内为空的状态下,如果对栈继续进行取数据的操作,就会出错。

栈的“上溢”和“下溢”,可以总结为:栈满还存会“上溢”,栈空再取会“下溢”。

对于栈的两种表示方式来说,顺序栈两种情况都有可能发生;而链栈由于“随时需要,随时申请空间”的存储结构,不会出现“上溢”的情况。

顺序栈

顺序栈的实现采用的是数组。

在顺序栈中设定一个随时指向栈顶元素的变量(一般命名为 top ),当 top 的值为 -1 时,说明数组中没有数据,即栈中没有数据元素,为“空栈”;只要数据元素进栈,top 就加 1 ;数据元素出栈, top 就减 1 。

例如,使用顺序栈的存储结构将(’a’,’b’,’c’,’d’)四个元素逐个压栈并输出栈顶元素。

实现代码:

#include <stdio.h>
//元素elem进栈
int push(char *a, int top, char elem)
{
a[++top] = elem;
return top;
}
//数据元素出栈
int pop(char *a, int top)
{
if (top == -)
  {
printf("空栈");
return -;
}
printf("弹栈元素:%c\n", a[top]);
top--;
return top;
}
int main()
{
char a[];
int top = -;
top=push(a, top, 'a');
top=push(a, top, 'b');
top=push(a, top, 'c');
top=push(a, top, 'd');
top=pop(a, top);
top=pop(a, top);
top=pop(a, top);
top=pop(a, top);
top=pop(a, top);
return ;
}
输出结果:
弹栈元素:d
弹栈元素:c
弹栈元素:b
弹栈元素:a
空栈

链栈

链栈,用线性表的链式存储结构实现。

链栈一般不需要创建头结点,头结点会增加程序的复杂性,只需要创建一个头指针就可以了。

用链表表示栈时,用链表头结点的一端作为栈的栈顶端,这样做的好处是当数据元素压栈或者弹栈时,直接使用头指针就可以完成,不需要增设额外的指针。

例如,用链栈实现将(’a’,’b’,’c’,’d’)四个数据元素压栈,再依次弹栈:

#include <stdio.h>
#include <stdlib.h>
typedef struct lineStack
{
char data;
struct lineStack *next;
}lineStack;
lineStack* push(lineStack * stack,char a)
{
lineStack *line = (lineStack*)malloc(sizeof(lineStack));
line->data = a;
line->next = stack;
stack = line;
return stack;
}
lineStack *pop(lineStack *stack)
{
if (stack)
  {
lineStack *p = stack;
stack = stack->next;
printf("弹栈元素:%c ", p->data);
if (stack)
     {
printf("栈顶元素:%c\n", stack->data);
}
     else
     {
  printf("栈已空\n");
}
free(p);
}
   else
   {
printf("栈内没有元素");
return stack;
}
return stack;
}
int main()
{
lineStack *stack = NULL;
stack = push(stack, 'a');
stack = push(stack, 'b');
stack = push(stack, 'c');
stack = push(stack, 'd');
stack = pop(stack);
stack = pop(stack);
stack = pop(stack);
stack = pop(stack);
stack = pop(stack);
return ;
}
输出结果:

弹栈元素:d 栈顶元素:c
弹栈元素:c 栈顶元素:b
弹栈元素:b 栈顶元素:a
弹栈元素:a 栈已空
栈内没有元素

总结

实际生活中使用手机时,屏幕页面的跳转使用的就是栈结构(跳转页面时,前一个页面会被存储到栈中;做回退操作时会回到上一个页面,这是进栈页面出栈的效果)。另外在求 n!时,可以通过函数的递归来实现,这个过程的底层就用到了栈结构。

除此之外,数制转换和括号匹配问题也可以用栈来解决(下节介绍)。

数据结构11: 栈(Stack)的概念和应用及C语言实现的更多相关文章

  1. Python与数据结构[1] -> 栈/Stack[0] -> 链表栈与数组栈的 Python 实现

    栈 / Stack 目录 链表栈 数组栈 栈是一种基本的线性数据结构(先入后出FILO),在 C 语言中有链表和数组两种实现方式,下面用 Python 对这两种栈进行实现. 1 链表栈 链表栈是以单链 ...

  2. 数据结构之栈(Stack)

    什么是栈(Stack) 栈是一种遵循特定操作顺序的线性数据结构,遵循的顺序是先进后出(FILO:First In Last Out)或者后进先出(LIFO:Last In First Out). 比如 ...

  3. [ACM训练] 算法初级 之 数据结构 之 栈stack+队列queue (基础+进阶+POJ 1338+2442+1442)

    再次面对像栈和队列这样的相当基础的数据结构的学习,应该从多个方面,多维度去学习. 首先,这两个数据结构都是比较常用的,在标准库中都有对应的结构能够直接使用,所以第一个阶段应该是先学习直接来使用,下一个 ...

  4. Python与数据结构[1] -> 栈/Stack[1] -> 中缀表达式与后缀表达式的转换和计算

    中缀表达式与后缀表达式的转换和计算 目录 中缀表达式转换为后缀表达式 后缀表达式的计算 1 中缀表达式转换为后缀表达式 中缀表达式转换为后缀表达式的实现方式为: 依次获取中缀表达式的元素, 若元素为操 ...

  5. 线性数据结构之栈——Stack

    Linear data structures linear structures can be thought of as having two ends, whose items are order ...

  6. 数据结构之栈(stack)的实现

    一.栈 1.定义 栈的英文为(stack),是一种数据结构 栈是一个先入后出(FILO-First In Last Out)的有序列表. 栈(stack)是限制线性表中元素的插入和删除只能在线性表的同 ...

  7. C# 数据结构 栈 Stack

    栈和队列是非常重要的两种数据结构,栈和队列也是线性结构,线性表.栈和队列这三种数据结构的数据元素和元素的逻辑关系也相同 差别在于:线性表的操作不受限制,栈和队列操作受限制(遵循一定的原则),因此栈和队 ...

  8. 【Java数据结构学习笔记之二】Java数据结构与算法之栈(Stack)实现

      本篇是java数据结构与算法的第2篇,从本篇开始我们将来了解栈的设计与实现,以下是本篇的相关知识点: 栈的抽象数据类型 顺序栈的设计与实现 链式栈的设计与实现 栈的应用 栈的抽象数据类型   栈是 ...

  9. 数据结构之栈(stack)

    1,栈的定义 栈:先进后出的数据结构,如下图所示,先进去的数据在底部,最后取出,后进去的数据在顶部,最先被取出. 栈常用操作: s=Stack() 创建栈 s.push(item) 将数据item放在 ...

随机推荐

  1. c语言-单链表(一)

    定义节点: typedef struct Node { int data; Node* pNext; }NODE, *PNODE; 细节说明,PNode 就代表struct Node* ,上面的表单是 ...

  2. 线性表的链式存储——C语言实现

    SeqList.h #ifndef _WBM_LIST_H_ #define _WBM_LIST_H_ typedef void List; typedef void ListNode; //创建并且 ...

  3. docker 笔记 (5)常用命令

    images    显示镜像列表 history   显示镜像构建历史 commit    从容器创建新镜像 build     从 Dockerfile 构建镜像 tag       给镜像打 ta ...

  4. js常见的字符串及数组处理

    最近工作设计前台比较多,由于好久没动前台,或者使用前台框架习惯了,js有点生,将常见的字符串处理忘了,在这里整理一下常见的,以便于查阅: 1.substr():字符串分割,第一个是开始的下标,第二个是 ...

  5. 工作的时候用到spring返回xml view查到此文章亲测可用

    spring mvc就是好,特别是rest风格的话,一个 org.springframework.web.servlet.view.ContentNegotiatingViewResolver就可以根 ...

  6. sharepoint 2013创建网站集,域帐户无法访问,只有administrator可以访问

    解决方法: 1.创建WEB应用程序时,可配置帐户必须为域帐户 2.确定关闭防火墙(这是重点) 我在测试时发现80端口和30714端口在其它同事的电脑上(域帐户)都可以访问,除这两个端口以后都无法访问, ...

  7. 怎么把网页保存为pdf文件

    不就是用chrome浏览器打印功能,然后保存为pdf就可以了吗? 对于一些结构简单的比如,RFC文档这样操作一般没什么问题,对于一些有浮动元素的网页就不好说了,必须先用chrome的审查元素把一些不必 ...

  8. 高性能MySQL笔记-第5章Indexing for High Performance-003索引的作用

    一. 1. 1). Indexes reduce the amount of data the server has to examine.2). Indexes help the server av ...

  9. ZROI2018普转提day2t4

    传送门 分析 考场上暴力水过好评... 然后我的st表查询似乎是log的,然后log三方跑的比log方快,qwq. 我们发现如果一个区间的最小值就是这个区间的gcd,则这个区间合法.所以我们二分区间长 ...

  10. CF 959E Mahmoud and Ehab and the xor-MST

    第一反应是打表找规律……(写了个prim)但是太菜了没找到 于是开始怀疑是不是我的表错了,又写了一个克鲁斯卡尔,然后结果是一样的……(捂脸) 后来从克鲁斯卡尔的算法上发现了一点东西,发现只有2的幂次长 ...