热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

数据结构第三章,栈、队列、数组,期末不挂科指南,第3篇

数据结构第三章,栈、队列、数组,期末不挂科指南,第3篇,Go语言社区,Golang程序员人脉社

文章目录

    • 学习目标
      • 基本概念
        • 栈的基本运算
      • 栈的顺序实现
      • 双栈
      • 栈的链接实现
    • 考试要点
    • 小结
    • 关注我吧


学习目标

自考重点、期末考试必过指南,这篇文章让你理解什么是栈、什么是队列、什么是数组

掌握栈、队列的顺序存储结构和链式存储结构

掌握栈、队列的基本操作在顺序存储结构和链式存储结构上的实现

掌握矩阵的压缩存储

今天核心咱们先把栈搞清楚


栈和队列可以看做是特殊的线性表 。它们的特殊性表现在它们的基本运算是线性表运算的子集,它们是运算受限的线性表



栈(Stack)是运算受限的线性表,这种线性表上的插入和删除操作限定在表的一端进行


基本概念

栈顶:允许插入和删除的一端

栈尾:另一端

空栈:不含任何数据元素的栈

栈顶元素:处于栈顶位置的数据元素

书中的例子比较形象

洗盘子,放盘子,每次只能从这一摞盘子的最上面拿走,这就是栈的基本操作

看重点:栈—> ==后进先出(Last In First Out) LIFO 原则 ==

所以栈被称作 后进先出线性表 (后进先出表)

栈的插入和删除运算 分为成为 进栈和 出栈


栈的基本运算


  • 初始化 InitStack(S) 构造一个空栈S

  • 判断栈空 EmptyStack(S) 若栈为空,返回1,否则返回0

  • 进栈Push(S,x) 将元素x插入栈S中

  • 出栈Pop(S) 删除栈顶元素

  • 取栈顶GetTop(S) 返回栈顶元素

栈的顺序实现

这里面有两个小知识点在写代码之前需要掌握

空栈做出栈操作,会出现问题,叫做“下溢”

满栈做进栈操作,会出现问题,叫做“上溢”

接下来我们就用C语言实现一下

初始化一个空栈

#include
#include
// 声明顺序栈的容量
const int maxsize = 6;
struct seqtack{
int *data; //存储栈中元素的数组
int top; // 栈顶下标
};
typedef struct seqtack Seq;
// 初始化操作
Seq init(Seq s){
printf("初始化函数运行n");
s.data = (int*)malloc(maxsize*sizeof(int));//动态分配存储空间
if(!s.data){
printf("初始化失败");
exit(0);
}
s.top = 0;
return s;
}

注意事项

初始化需要动态分配空间,并且需要让top值等于0

判断栈空


//判断栈空
int empty(Seq s){
printf("判断栈空n");
if(s.top == 0){
return 1;
}
return 0;
}

这个比较简单了,只需要判断s.top值就可以了

进栈操作

//进栈操作
Seq push(Seq s,int x){
printf("进栈操作n");
// 判断栈是否满了

if(s.top==maxsize-1){
printf("栈满");
return s;
}
else{

printf("正在插入数据%dn",x);
s.data[s.top] = x;
s.top++;
return s;
}

}

出栈操作

//出栈操作
Seq pop(Seq s,int *e){
if(empty(s)){
printf("栈空n");
exit(0);
}
else{
*e = s.data[s.top-1];
s.top--;
return s;
}
}

进栈和出栈,这部分内容一定要好好的理解,其实也是比较简单的,就是添加元素和删除元素

打印栈中元素与获取栈顶元素

// 打印栈中元素
void display(Seq s){
if(empty(s)){
printf("栈空n");
exit(0);
}
else{
printf("开始打印n");
int num = 0;
while(num < s.top){
printf("现在的元素是:%dn",s.data[num++]);
}
}
}
// 获取栈顶元素
int gettop(Seq s){
if(empty(s)){
exit("栈空n");
}
else{
return s.data[s.top-1];
}
}

主函数测试代码

int main()
{
printf("代码运行中n");
Seq s ;
s = init(s);

//插入两个元素
s = push(s,1);
s = push(s,2);

display(s);
int e;
s = pop(s,&e);
printf("删除的元素是:%dn",e);

display(s);

return 0;
}

双栈

书中还提到了双栈,不过这个不是重点了,你要知道的是,双栈的两个栈底分别设置在数组的两端,栈顶分为是top1,top2

两个栈顶在中间相遇,条件为 (top1+1=top2)发生上溢

判断栈空条件呢?

一个是 top=0 另一个是top = maxsize -1 这个要注意一下即可


栈的链接实现

栈的链接实现称为链栈。链栈 可以用带头结点的单链表来实现,链栈不用预先考虑容量的大小


链栈将链表头部作为栈顶的一端,可以避免在实现数据“入栈”和“出栈”操作时做大量遍历链表的耗时操作


链表的头部作为栈顶,有如下的好处


  1. 入栈 操作时,只需要将数据从链表的头部插入即可

  2. 出栈 操作时,只需要删除链表头部的首结点即可

结论:链表实际上就是一个只能采用头插法插入或删除的链表

例子:将元素1,2,3,4依次入栈,等价于将各元素采用头插法依次添加到链表中

在这里插入图片描述


图片来源网络


完整代码如下


由于比较简单,直接贴上了


#include
#include
typedef struct node{
int data; //数据域
struct node *next; //链域
} LkStk;
//初始化
void init(LkStk *ls){
printf("初始化操作n");
ls = (LkStk *)malloc(sizeof(LkStk));
ls->next = NULL;
}
// 进栈
void push(LkStk *ls,int x){
printf("进栈操作n");
LkStk *temp;
temp = (LkStk*)malloc(sizeof(LkStk));//给temp新申请一块空间
temp->data = x;
temp->next = ls->next;
ls->next = temp;
printf("%d进栈成功n",x);
}
int empty(LkStk *ls){
if(ls->next ==NULL){
return 1;
}
else return 0;
}
// 出栈
int pop(LkStk *ls){
LkStk *temp;
//判断栈是否为空
if(!empty(ls)){
temp= ls->next; // 准备出栈的元素指向ls的下一结点
ls->next = temp->next; // 原栈顶的下一个结点称为新的栈顶
printf("栈顶元素:%dn",temp->data);
free(temp); //释放原栈顶的结点空间
return 1;
}
return 0;
}
int main()
{
LkStk ls;
init(&ls);

push(&ls,1);
push(&ls,2);

pop(&ls);
pop(&ls);
return 0;
}

这就是链栈的基本进栈和出栈了,当然,我们还可以获取一下栈顶元素


考试要点

在自考或者期末考试中,容易出现的一种题是手写入栈和出栈

例如


设一个链栈的输入序列为A、B、C,试写出所得到的所有可能的输出序列,即输出出栈操作的数据元素序列


写答案的时候,记住先进后出原则

从A开始写

A进,A出,B进,B出,C进,C出

A进,B进,B出,C进,C出,A出

… …

继续写下去就可以了,一定不要出现A进,B进,B出,C进,A出 注意,A出不去,A前面有C呢

在来一个例题


如图所示,在栈的输入端元素的输入顺序为A,B,C,D,进栈过程中可以退栈,写出在栈的输出端以A开头和以B开头的所有输出序列。
在这里插入图片描述


这个就是把A开头和B开头的都写出来


  1. ABCD、ABDC、ACBD、ACDB、ADCB

  2. BACD、BADC、BCAD、BCDA、BDCA

主要仔细,就能写对,套路就是,先进后出



小结

栈是只能在一端(栈顶)进行插入和删除运算的线性表,具有后进先出特征。

以顺序存储结构实现的栈称为顺序栈,以链式存储结构实现的栈称为链栈。

顺序栈需要预先定义栈的大小,在难以估计栈的大小时,可以采用链栈,链栈是用单链表实现。一般地,将栈顶设在链表的表头一端,栈底设置在链表的表尾。栈适合与具有后进先出特征的问题。

如程序实现递归,函数调用等。


关注我吧

在这里插入图片描述




推荐阅读
  • 数据结构入门:栈的基本概念与操作
    本文详细介绍了栈这一重要的数据结构,包括其基本概念、顺序存储结构、栈的基本操作(如入栈、出栈、清空栈和销毁栈),以及如何利用栈实现二进制到十进制的转换。通过具体代码示例,帮助读者更好地理解和应用栈的相关知识。 ... [详细]
  • 题目Link题目学习link1题目学习link2题目学习link3%%%受益匪浅!-----&# ... [详细]
  • 本文介绍如何使用Objective-C结合dispatch库进行并发编程,以提高素数计数任务的效率。通过对比纯C代码与引入并发机制后的代码,展示dispatch库的强大功能。 ... [详细]
  • 题目描述:给定n个半开区间[a, b),要求使用两个互不重叠的记录器,求最多可以记录多少个区间。解决方案采用贪心算法,通过排序和遍历实现最优解。 ... [详细]
  • 扫描线三巨头 hdu1928hdu 1255  hdu 1542 [POJ 1151]
    学习链接:http:blog.csdn.netlwt36articledetails48908031学习扫描线主要学习的是一种扫描的思想,后期可以求解很 ... [详细]
  • Splay Tree 区间操作优化
    本文详细介绍了使用Splay Tree进行区间操作的实现方法,包括插入、删除、修改、翻转和求和等操作。通过这些操作,可以高效地处理动态序列问题,并且代码实现具有一定的挑战性,有助于编程能力的提升。 ... [详细]
  • 本题涉及一棵由N个节点组成的树(共有N-1条边),初始时所有节点均为白色。题目要求处理两种操作:一是改变某个节点的颜色(从白变黑或从黑变白);二是查询从根节点到指定节点路径上的第一个黑色节点,若无则输出-1。 ... [详细]
  • Linux设备驱动程序:异步时间操作与调度机制
    本文介绍了Linux内核中的几种异步延迟操作方法,包括内核定时器、tasklet机制和工作队列。这些机制允许在未来的某个时间点执行任务,而无需阻塞当前线程,从而提高系统的响应性和效率。 ... [详细]
  • 深入探讨CPU虚拟化与KVM内存管理
    本文详细介绍了现代服务器架构中的CPU虚拟化技术,包括SMP、NUMA和MPP三种多处理器结构,并深入探讨了KVM的内存虚拟化机制。通过对比不同架构的特点和应用场景,帮助读者理解如何选择最适合的架构以优化性能。 ... [详细]
  • Codeforces Round #566 (Div. 2) A~F个人题解
    Dashboard-CodeforcesRound#566(Div.2)-CodeforcesA.FillingShapes题意:给你一个的表格,你 ... [详细]
  • 微软Exchange服务器遭遇2022年版“千年虫”漏洞
    微软Exchange服务器在新年伊始遭遇了一个类似于‘千年虫’的日期处理漏洞,导致邮件传输受阻。该问题主要影响配置了FIP-FS恶意软件引擎的Exchange 2016和2019版本。 ... [详细]
  • 本题旨在通过给定的评级信息,利用拓扑排序和并查集算法来确定全球 Tetris 高手排行榜。题目要求判断是否可以根据提供的信息生成一个明确的排名表,或者是否存在冲突或信息不足的情况。 ... [详细]
  • 本文详细介绍了C语言中的指针,包括其基本概念、应用场景以及使用时的优缺点。同时,通过实例解析了指针在内存管理、数组操作、函数调用等方面的具体应用,并探讨了指针的安全性问题。 ... [详细]
  • 本文深入探讨了POJ2762问题,旨在通过强连通分量缩点和单向连通性的判断方法,解决有向图中任意两点之间的可达性问题。文章详细介绍了算法原理、实现步骤,并附带完整的代码示例。 ... [详细]
  • 本文探讨了如何在模运算下高效计算组合数C(n, m),并详细介绍了乘法逆元的应用。通过扩展欧几里得算法求解乘法逆元,从而实现除法取余的计算。 ... [详细]
author-avatar
不需要忆jf
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有