数据结构-3、栈、队列和数组

news2024/11/26 7:34:30

3.1、栈

3.1.1、栈的基本概念:

1、栈的定义:

​ 栈是只允许在一端进行插入或删除操作的线性表。首先,栈是一种线性表,但限定这种线性表只能在某一端进行插入和删除操作,如下图:

在这里插入图片描述

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

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

​ 空栈。不包含任何元素的空表。

​ 假设某个栈 S = ( a 1 , a 2 , a 3 , a 4 , a 5 ) S=(a_1,a_2,a_3,a_4,a_5) S=(a1,a2,a3,a4,a5),如上图所示,则 a 1 a_1 a1为栈底元素, a 5 a_5 a5为栈顶元素。由于栈只能在栈顶进行插入和删除操作,进栈次序依次为 a 1 , a 2 , a 3 , a 4 , a 5 a_1,a_2,a_3,a_4,a_5 a1,a2,a3,a4,a5,而出栈次序则与入栈次序相反。由此可见,栈的操作特性可以明显地概括为后进先出(LIFO)。

​ 栈的数学性质:n 个不同元素进栈,出栈元素不同排列的个数为 1 n + 1 C 2 n n \frac{1}{n+1}C^n_2n n+11C2nn 。上述公式称为卡特兰数,可采用数学归纳法证明。

2、栈的基本操作:

​ 栈的基本操作:

InitStack(&S)		//初始化一个空栈。
StackEmpty(S)		//判断一个栈是否为空,若栈 S 为空则返回 ture ,否则返回 false。
Push(&S,x)			//进栈,若栈 S 未满,则将 x 加入使之成为新栈顶。
Pop(&S,&x)			//出栈,若栈 S 非空,则弹出栈顶元素,并用 x 返回。
GetTop(S,&x)		//读取栈顶元素,若栈 S 非空,则用 x 返回栈顶元素。
DestroyStack(&S)	//销毁栈,并释放栈 S 占用的存储空间(“& 表示引用调用”)。

3.1.2、栈的顺序存储结构:

​ 栈是一种操作受限的线性表,类似于线性表,它也有对应的两种存储方式。

1、顺序栈的实现:

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

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

#define MaxSize 50
typedef struct{
    Elemtype data[MaxSize];
    int top;
} SqStack;

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

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

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

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

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

2、顺序栈的基本运算:

​ 栈操作的示意图如下图所示:(a)是空栈,(c)是 A、B、C、D、E 共 5 个元素依次入栈后的结果,(d)是在(c)之后 E、D、C相继出栈,此时栈中还有 2 个元素,或许最近出栈的元素 C、D、E仍在原先的单元存储着,但 top 指针已经指向了新的栈顶,元素 C、D、E 已不在栈中。

在这里插入图片描述

​ 下面是顺序栈上常用的基本运算实现:

#include "stdio.h"

#define MaxSize 50

typedef struct{
    int data[MaxSize];
    int top;
} SqStack;

void InitStack(SqStack *S);
int StackEmpty(SqStack *S);
int Push(SqStack *S,int x);
int Pop(SqStack *S,int *x);
int GetTop(SqStack *S,int *x);

int main(){
    SqStack S;
    int x;
    InitStack(&S);
    for (int i = 1;i <= 6;i++){
        Push(&S,i);
    }
    if(GetTop(&S,&x))
        printf("%d",x);
}

//初始化栈
void InitStack(SqStack *S){
    S->top = -1;
}

//判断栈是否为空
int StackEmpty(SqStack *S){
    if (S->top == -1)
        return 1;
    else
        return 0;
}

//入栈操作
int Push(SqStack *S,int x){
    if(S->top == MaxSize -1)
        return 0;
    S->data[++S->top] = x;
    return 1;
}

//出栈操作
int Pop(SqStack *S,int *x){
    if(S->top == -1)
        return 0;
    *x = S->data[S->top--];
    return 1;
}

//读取栈顶元素
int GetTop(SqStack *S,int *x){
    if(S->top == -1)
        return 0;
    *x = S->data[S->top];
    return 1;
}

3、共享栈:

​ 利用栈底位置相对不变的特性,可让两个顺序栈共享一个以为数组空间,将两个栈的栈底分别设置在共享空间的两端,两个栈顶向共享空间的中间眼神,如下图:

在这里插入图片描述

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

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

3.1.3、栈的链式存储结构:

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

在这里插入图片描述

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

typedef struct Linknode{
    ElemType data;
    struct LinkNode *next;
} *LiStack;

​ 采用链式存储,便于结点的插入与删除。链栈的操作与链表类似,入栈和出栈的操作都在链表的表头进行。需要注意的是,对于带头结点和不带头结点的链栈,具体的实现会有所不同。

3.2、队列;

3.2.1、队列的基本概念:

1、队列的定义:

​ 队列,也是一种操作受限的线性表,只允许在表的一端进行插入,而表的另一端进行删除。向队列中插入元素成为入队或进队;删除元素称为出队或离队。这和我们日常生活中的排队时一致的,最早排队的也是最早离队的,其操作的特性是先进先出(FIFO),如下图:

在这里插入图片描述

​ 对头。允许删除的一端,又称队首。

​ 队尾。允许插入的一端。

​ 空队列。不含任何元素的空表。

2、队列常见的基本操作:

InitQueue(*Q)		//初始化队列,构造一个空队列 Q。
QueueEmpty(*Q)		//判队列空,若队列 Q 为空返回 true ,否则返回 false。
EnQueue(*Q,x)		//入队,若队列 Q 未满,将 x 加入,使之成为新的队尾。
DeQueue(*Q,*x)		//出队,若队列 Q 非空,删除队头元素,并用 x 返回。
GetHead(*Q,*x)		//读队头元素,若队列 Q 非空,则将对头元素赋值给 x。

3.2.2、队列的顺序存储结构:

1、队列的顺序存储:

​ 队列的顺序实现是指分配一块连续的存储单位存放队列的元素,并附设两个指针:队头指针 front 指向队头元素,队尾指针 rear 指向队尾元素的下一个位置。

​ 队列的顺序存储类型可描述为:

#define MaxSize 50
typedef struct{
    ElemType data[MaxSize];
    int front,rear;
} SqQueue;

​ 初始时:Q.front = Q.rear = 0。

​ 进队操作:队不满时,先送值到队尾元素,再将队尾指针加 1。

​ 出队操作:队不空时,先取队头元素值,再将队头指针加 1.

​ 如下图(a)所示为列表的初始状态,有 Q.frontQrear0成立,该条件可以作为队列判断空的条件。但能否用 Q.rear==MaxSize 作为队列满的条件呢?显然不能,如图(d),队列中仅有一个元素,但扔满足该条件。这时入队出现“上溢出”,但这种溢出不是真正的溢出,在 data 数组中依然存在可以存放元素的空位置,所以时一种“假溢出”。

在这里插入图片描述

2、循环队列:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1826179.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Zombie Animations Set

僵尸动画合集,包括成对攻击/抓取、各种移动方式、爬行、击中反应、死亡动画等。 生产说明 动画总数:99(包括22个位置变化) 配对动画:36 攻击次数:6次 爬网:9 命中反应:6 空转:14 行程2 跑步次数:9次 短跑:2 匝数:3 步行次数:12次 免责声明 任何游戏玩法蓝图都不包…

【电路笔记】-共集极放大器

共集极放大器 文章目录 共集极放大器1、概述2、等效电路3、电压增益4、偏置方法5、输入阻抗6、输出阻抗7、电流增益8、示例:共集电极放大器的电压、电流和功率增益9、达林顿对10、总结1、概述 本文介绍另一种用于放大信号的双极晶体管架构,通常称为共集电极放大器 (CCA)。 C…

深入解析Prometheus架构:打造高效监控系统的终极指南

1. Prometheus Server&#xff08;Prometheus服务器&#xff09; 技术原理&#xff1a; Retrieval&#xff08;检索模块&#xff09;&#xff1a;定期从配置的Targets&#xff08;目标&#xff09;拉取监控数据。使用HTTP协议&#xff0c;通过拉取的方式收集数据。TSDB&#…

如何通过抖音自动评论精准获客实现业务增长?这些方法值得一试!

在当今竞争激烈的商业环境中&#xff0c;企业若想脱颖而出&#xff0c;就必须掌握精准获客的艺术。精准获客&#xff0c;即通过精确的市场定位和营销策略&#xff0c;吸引并保留最有可能成为客户的目标群体。它不仅能提高转化率&#xff0c;还能有效降低营销成本&#xff0c;是…

【人工智能】开发AI可能获刑?加州1047草案详解

引言 随着人工智能&#xff08;AI&#xff09;技术的飞速发展&#xff0c;其应用领域不断扩展&#xff0c;但同时也引发了诸多争议和监管问题。近期&#xff0c;加州参议院以32比1的压倒性投票通过了1047号草案&#xff0c;又称《前沿人工智能模型安全可靠创新法案》。这一草案…

Java---认识异常

欢迎大家来观看本博课------Java------认识异常。1.异常的概念和体系结构 1.异常的概念和体系结构 1.1 异常的概念 在Java中&#xff0c;在程序执行过程中发生的不正常行为称为异常。如在之前我们经常遇到的算数异常&#xff08;ArithmeticException&#xff09;、数组越界…

金融行业的等保测评要求

在金融行业中&#xff0c;网络安全问题非常普遍&#xff0c;如恶意攻击、病毒感染、数据泄露等。这些问题可能会导致金融机构的信息系统瘫痪&#xff0c;造成巨大的经济损失&#xff0c;甚至影响国家金融稳定。因此&#xff0c;金融机构应该高度重视网络安全问题&#xff0c;采…

使用libpurple函数库接入服务器

代码; #define CUSTOM_USER_DIRECTORY "/dev/null" // 定义用户目录 #define CUSTOM_PLUGIN_PATH "" // 定义插件目录 #define PLUGIN_SAVE_PREF "/purple/nullclient/plugins/saved" // 定义插件头目录 #define UI_ID "nullc…

DELL服务器插入新磁盘、创建虚拟磁盘、挂载磁盘步骤

文章目录 一、磁盘清理&#xff08;可选&#xff0c;针对新硬盘是Foreign状态&#xff09;1、进入VD Mgmt2、清理新硬盘配置 二、创建虚拟磁盘1、进入Device Settings2、创建虚拟磁盘 三、挂载磁盘到系统1、分区磁盘&#xff08;注意实际磁盘的名称&#xff09;2、格式化分区3、…

跨境电商中的IP隔离是什么?怎么做?

一、IP地址隔离的概念和原理 当我们谈论 IP 地址隔离时&#xff0c;我们实际上是在讨论一种网络安全策略&#xff0c;旨在通过技术手段将网络划分为不同的区域或子网&#xff0c;每个区域或子网都有自己独特的 IP 地址范围。这种划分使网络管理员可以更精细地控制哪些设备或用…

微服务feign组件学习

手写不易&#xff0c;对您有帮助。麻烦一键三连。也欢饮各位大料指正&#xff0c;交流。 微服务feign组件学习 1.概念1.1 feign 概念1.2 Ribbon概念 2.使用2.1 集成feign2.1.1 maven依赖2.1.2 项目结构 2.2 使用2.2.1 定义feign接口2.2.2 消费端服务调用2.2.3 消费端扫描feig…

Java面试题汇总(持续更新.....)

Java面试题 1. JVM & JDK & JRE Java虚拟机&#xff08;JVM&#xff09;是运行Java字节码的虚拟机&#xff0c;JVM有针对不同系统的特定实现&#xff0c;目的是使用相同的字节码&#xff0c;他们都会给出相同的结果。字节码和不同系统的JVM实现是Java语言“一次编译、…

个人网站制作 Part 25 添加实时聊天功能 | Web开发项目添加页面缓存

文章目录 &#x1f469;‍&#x1f4bb; 基础Web开发练手项目系列&#xff1a;个人网站制作&#x1f680; 添加实时聊天功能&#x1f528;使用聊天服务&#x1f527;步骤 1: 选择聊天服务&#x1f527;步骤 2: 安装Socket.io&#x1f527;步骤 3: 创建Socket.io服务器 &#x1…

抽奖系统源码_微信抽奖系统PHP源码开源

介绍&#xff1a; 微信抽奖系统源码是一个以php MySQL进行开发的手机抽奖系统源码。用途&#xff1a;适合做推广营销、直播、粉丝抽奖。 功能介绍&#xff1a; 1、后台可以设置每个抽奖用户的抽奖次数,后台添加设置奖品,适和企业和商场搞活动,后台添加用户&#xff0c;才能抽…

如何应对缺失值带来的分布变化?探索填充缺失值的最佳插补算法

本文将探讨了缺失值插补的不同方法&#xff0c;并比较了它们在复原数据真实分布方面的效果&#xff0c;处理插补是一个不确定性的问题&#xff0c;尤其是在样本量较小或数据复杂性高时的挑战&#xff0c;应选择能够适应数据分布变化并准确插补缺失值的方法。 我们假设存在一个…

【多线程】Thread类及其基本用法

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 文章目录 1. Java中多线程编程1.1 操作系统线程与Java线程1.2 简单使用多线程1.2.1 初步创建新线程代码1.2.2 理解每个…

小功率无变压器电源设计

采用无变压器电源解决方案为低功率电路提供所需电源通常是有利的。 事实上&#xff0c;如果负载电流只有几十毫安&#xff0c;则可以将输入交流电压转换为直流电压&#xff0c;而无需使用大型、昂贵且笨重的变压器。不带变压器的替代方案也更便宜、更轻并且占地面积更小。无变…

深入剖析人才管理的关键要素:“选、用、育、留”四大核心要素

在当今这个日新月异的商业时代&#xff0c;企业的成功不再仅仅取决于资金、技术或市场策略&#xff0c;而更多地依赖于企业所拥有的人才资源。有效的人才管理策略&#xff0c;尤其是“选、用、育、留”四大核心要素&#xff0c;已成为推动企业持续发展的关键。 一、选&#xff…

28.启动与暂停程序

上一个内容&#xff1a;27.设计注入功能界面 以它 27.设计注入功能界面 的代码为基础进行修改 点击添加游戏按钮之后就把游戏启动了 CWndINJ.cpp文件中修改&#xff1a; void CWndINJ::OnBnClickedButton1() {// TODO: 在此添加控件通知处理程序代码/*ExeLst.InsertItem(0, L…

虚函数机制-动态绑定的应用

虚函数使得程序在运行的时候根据指针指向对象的类型来确定调用哪个函数。 下图中&#xff1a;都为静态绑定。因为在编译器就确定了可以调用的函数 此时当基类指针指向派生类对象时&#xff0c;因为没有virtual关键字&#xff0c;所以在编译阶段就根据指针类型确定了要指向的函…