栈、队列

article/2025/10/16 0:30:17

      顺序栈,即栈的顺序存储结构是利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素,同时附设指针top指示栈项元素在顺序栈中的位置。通常的习惯做法是以top=0表示空栈,鉴于C语言中数组的下标约定从0开始,则当以C作描述语言时,如此设定会带来很大不便;另一方面由于栈在使用过程中所需最大空间的大小很难估计,因此,一般来说,在初始化设空栈时不应限定栈的最大容量。一个较合理的做法是:先为栈分配一个基本容量,然后在应用过程中,当栈的空间不够使用时再逐段扩大。为此,可设定两个常量:STAC_INT_SIZE(存储空间初始分配)和STACKINCREMENT(存储空间分配增量),并以下述类型说明作为顺序栈的定义。

 

typedef struct{
  SElemType *base;
  SElemType *top;
  int stackseze;
}SqStack;

 

其中,stacksize只是栈的当前可使用的最大容量。栈的初始化操作为:按设定的初始分配量进行第一次存储分配,base可称为栈底指针,在顺序栈中,它始终指向栈底的位置,若base的值为NULL,则表明栈结构不存在。称top为栈顶指针,其初值指向栈底,即top=base可作为栈空的标记,每当插入新的栈顶元素时,指针top增1;删除栈顶元素时,指针top减1,因此,非空栈中的栈顶指针始终在栈顶元素的下一个位置上。图1展示了顺序栈中数据元素和栈顶指针之间的对应关系。

图3.2

图1 栈顶指针和栈中元素之间的关系

以下是顺序栈的模块说明。

//=====ADT Stack 的表示与实现 =====
//-----栈的顺序存储表示-----
#define STACK_INIT_SIZE 100; //存储空间初始分配量
#define STACKINCREMENT 10; //存储空间分配增量
typedef struct{
  SElemType *base; //在栈构造之前和销毁之后,base的值为NULL
  SElemType *top; //栈顶指针
  int stacksize; //当前已分配的存储空间,以元素为单位
}SqStack;
 
//-----基本操作的函数原型说明(针对几个易错易考的)-----
Status GetTop (SqStack S, SElemType &e);
   //若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERRO
Status Push (SqStack &S, SElemType e);
   //插入元素e为新的栈顶元素
Status Pop (SqStack &S, SElemType &e);
   // 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR 

 

    栈的引入简化了程序设计的问题,划分了不同的关注层次,使思考范围缩小了。而用数组不仅掩盖了问题的本质,还要分散精力去考虑数组下标增减等细节问题。(栈这个数据结构模型正是基于一些问题本质而构建的,具有了一些实际的模型含义,不像数组那样原始。

    队列是一种先进先出(first infirst out,缩写为FIFO)的线性表。它只允许在标的一端进行插入,而在另一端删除元素。这和我们日常生活中的排队是一致的,最早进入队列的元素最早离开。在队列中,允许插入的一端叫做队尾(rear),允许删除的一端则称为对头(front)(排队买票,窗口一端叫对头,末尾进队叫队尾)。

    用链表表示的队列称为链队列,如图2所示。一个链队列显然需要两个分别指向对头和队尾的指针(分别称为头指针和尾指针)才能唯一确定。这里,和线性表的单链表一样,为了操作方便起见,我们先给链队列添加一个头结点,并令头指针和尾指针均指向头结点,如图3(a)所示。链队列的操作即为单链表的插入和删除操作的特殊情况,只是尚需修改尾指针或头指针,图3(b)~(d)展示了这两种操作进行时指针变化的情况。下面给出链队列类型的模块说明。

                                 图3.10 图3.11

                                                           图2 链队列示意图                       图3 队列运算指针变化情况 (a)空队列;(b)元素x入队;(c)元素y入队;(d)元素x出队

 

//=====ADT Queue的表示与实现=====
//-----单链队列——队列的链式存储结构-----
typedef struct QNode{
    QElemType   data;
    struct QNode  *next;
}QNode, *QueuePtr;

typedef struct{
    QueuePtr front;  //对头指针
    QueuePtr rear;  //队尾指针
}LinkQueue;

//-----基本操作的函数原型说明(几个易错常考的)-----
Status GetHead(LinkQueue Q, QElemType &e)
   //若队列不空,则用e返回Q的对头元素,并返回OK;否则返回ERROR
Status EnQueue(LinkQueue &Q, QElemType e)
    //插入元素e为Q的新的队尾元素
Status DeQueue(LinkQueue &Q, QElemType &e)
    //若队列不空,则删除Q的对头元素,用e返回其值,并返回OK;
    //否则返回ERROR

     和顺序栈相类似,在队列的顺序存储结构中,除了用一组地址连续的存储单元依次存放从队列头到队列尾的元素之外,尚需附设两个指针front和rear分别之时队列头元素和队列尾元素的位置。为了在C语言中描述方便起见,在此我们约定:初始化建空队列时,令front=rear=0,每当插入新的队列尾元素时,“尾指针增1”;每当删除队列头元素时,“头指针增1”。因此,在非空队列中,头指针始终指向队列头元素,而尾指针始终指向队列尾元素的下一个位置。如图4所示。

图3.12 图4 头、尾指针和队列中元素之间的关系

(a)空队列;(b)J1、J2和J3相继入队列;(c)J1和J2相继被删除;(d)J4、J5和J6相继插入队列之后J3及J4被删除

    假设当前为队列分配的最大空间为6,则当队列处于图4(d)的状态时不可再继续插入新的队尾元素,否则会因数组越界而遭致程序代码被破坏。然而此时又不宜如顺序栈那样,进行存储再分配扩大数组空间,因为队列的实际可用空间并未占满。一个较巧妙的办法是将顺序队列臆造为一个环状的空间,如图5所示,称之为循环队列。指针和队列元素之间关系不变,如图6(a)所示循环队列中,队列头元素时J3,队列尾元素是J5,之后J6、J7和J8相继插入,则队列空间均被占满,如图6(b)所示,此时Q.front=Q.rear;反之,若J3、J4和J5相继从图6(a)的队列中删除,使队列呈“空”的状态,如图6(c)所示。此时亦存在关系式Q.front=Q.rear,由此可见,只凭等式Q.front=Q.rear无法判别队列空间是“空”还是“满”。可由两种处理方法:其一是另设一个标志位以区别队列是“空”还是“满”;其二是少用一个元素空间,约定以“队列头指针在队列尾指针的下一位置(指环状的下一位置)上”作为队列呈“满”状态的标志。

                                                                图3.13

图5 循环队列示意图

                                                    图3.14

图6 循环队列的头尾指针 (a)一般情况;(b)队列满时;(c)空队列;


    从上述分析可见,在C语言中不能用动态分配的一维数组来实现循环队列。如果用户的应用程序中设有循环队列,则必须为它设定一个最大队列长度;若用户无法预估所用队列的最大长度,则宜采用链队列。循环队列类型的模块说明如下:

//-----循环队列———队列的顺序存储结构-----
#define MAXQSIZE 100   //最大队列长度
typedef struct{
    QElemType *base;  //初始化的动态非配存储空间
    int front;        //头指针,若队列不空,指向队列的头元素
    int rear;         //尾指针,若队列不空,指向队列尾元素的下一个位置
}SqQueue;

 

//-----循环队列的基本操作的算法描述-----
Status InitQueue(SqQueue &Q){
    //构造一个空队列Q
    Q.base=(ElemType *)malloc(MAXQSIZE*sizeof(ElemType));
    if(!Q.base) exit (OVERFLOW);  // 存储分配失败
    Q.front=Q.rear=0;
    return OK;
}

int QueueLength(SqQueue Q){
    //返回Q的元素个数,即队列的长度
    return (Q.rear-Q.front+MAXQSIZE) % MAXQSIZE;
}

Status EnQueue(SqQueue &Q, QElemType e){
    //插入元素e为Q的新的队尾元素
    if((Q.rear+1) % MAXQSIZE == Q.front) return ERROR;  // 队列满
    Q.base[Q.rear]=e;
    Q.rear=(Q.rear+1) % MAXQSIZE;
    return OK;
}

Status DeQueue(SqQueue &Q, QElemType &e){
    //若队列不空,则删除Q的对头元素,用e返回其值,并返回OK;
    //否则返回ERROR
    if(Q.front==Q.rear)  return ERROR;
    e=Q.base[Q.front];
    Q.front=(Q.front+1) % MAXQSIZE;
    return OK;
}


http://chatgpt.dhexx.cn/article/1RpOXHFX.shtml

相关文章

栈、队列、数组

栈 定义 #include <stdio.h>/* 栈只允许在栈顶插入删除操作的线性表Last Insert First Out. */// 顺序栈#define MaxSize 10typedef struct {int data[MaxSize]; // 静态数组存放栈元素int top; // 栈顶指针 } SqStack; 栈顶指针指向栈顶元素的栈 空为-1 // 栈顶指针指…

使用SQL进行两个表关联查询(inner)

结果显示 公司类型表 公司表 实现方式 SELECTt_company.id,cName, typeName, cDescribe, t_company.modifyTime, t_company.createTime FROMt_company INNER JOIN t_company_type ON t_company.cType t_company_type.id代码解析 SELECT 显示字段,如果两个表都有字段,则需要…

sql进行两个关联表,根据其中一个表的一个属性进行条件查询查询

我最近遇到了表的查询,但是通过查询发现,网上的sql的大神,写的文章到底是什么玩意? 我打算自己写一个sql专栏,特意讲解sql的使用,来帮助大家 这篇文章技术指导为sql进行两个关联表,根据其中一个表的一个属性进行条件查询查询 假设只有两张表,其中一张表最后一个外键连…

SQL关联查询详解,SQL JOIN详解

关联查询&#xff0c;也称为多表查询&#xff0c;指两个或更多个表一起完成查询操作。 前提条件&#xff1a;这些一起查询的表之间是有关系的&#xff08;一对一、一对多&#xff09;&#xff0c;它们之间一定是有关联字段&#xff0c;这个关联字段可能建立了外键&#xff0c;也…

SQL-多表关联查询详解

为了在工作中能更顺利的使用多表关联查询&#xff0c;今天这篇博客就写这个内容了。 在讲解多表关联查询之前&#xff0c;先生成测试表。 登录scott用户&#xff0c;运行以下语句生成测试表。 create table ex1 as select * from emp; create table ex2 as select * from dept…

Mysql如何对两张表的相同字段,同时查询两张数据表

前言 假设现在有两张数据表 表1如下&#xff1a; 表2如下&#xff1a; 表1和表2同时都再mysql的情况下&#xff0c;只有他们的uuid是一样的&#xff0c;其他字段信息不同&#xff0c;现在需要用sql语句根据uuid&#xff0c;同时将符合要求的数据查询出来&#xff0c;怎么做呢&…

SQL- join多表关联

一、SQL 连接(JOIN) 1、笛卡尔积 &#xff08;1&#xff09;当多张表进行连接查询&#xff0c;没有任何条件限制的时候&#xff0c;最终查询结果条数&#xff0c;是多张表条数的乘积 如A表15条&#xff08;行&#xff09;数据&#xff0c;B表20条&#xff08;行&#xff09;…

SQL语言多表关联查询

新建两张表&#xff1a; 表1&#xff1a;student 截图如下&#xff1a; 表2&#xff1a;course 截图如下&#xff1a; &#xff08;此时这样建表只是为了演示连接SQL语句&#xff0c;当然实际开发中我们不会这样建表&#xff0c;实际开发中这两个表会有自己不同的主键。&…

[转载]静息态fMRI、DTI、VBM

[转载]静息态fMRI、DTI、VBM (2014-06-19 19:00:15) 转载▼ 标签&#xff1a; 转载 分类&#xff1a; fMRI-EEG 原文地址&#xff1a;静息态fMRI、DTI、VBM作者&#xff1a;426l 一、 简介 1、静息态fMRI数据处理学习内容 BOLD-fMRI技术自1990年发明至今&#xff0c;已经成…

用FSL进行VBM统计分析

用FSL进行VBM统计分析 总体步骤概览1.准备数据1.1 T1数据格式1.2 Template_list查看数据 2.剥头皮&#xff1a;fslvbm_1_bet3.数据分割生成模板&#xff1a;fslvbm_2_template4.后处理&#xff08;标准化、调制、平滑&#xff09;&#xff1a;fslvbm_3_proc5.统计检验5.2查看结…

[spm操作] VBM分析中,modulation的作用

本帖作为 《用Matlab和SPM批量处理被试的经验总结》 的一部分 目录贴请见 http://home.52brain.com/forum.ph ... 1&extra#pid158525 在VBM分析中&#xff0c;通常都有一个modulation的选项&#xff0c;有些滴友对这个步骤的作用有点不太理解。 我先举一个例子&#xff…

不同的工具包对Voxel-based morphometry (VBM)计算结果的影响

​《本文同步发布于“脑之说”微信公众号&#xff0c;欢迎搜索关注~~》 前期大量的MRI研究已经表明&#xff0c;精神分裂患者很多脑区的局部灰质体积&#xff08;regional grey matter volume&#xff09;出现异常变化&#xff0c;但是这些研究的结果似乎并不一致。而这种结果…

如何提取差异脑区的灰质体积与临床量表算相关?——基于体素的形态学方法(VBM)

基于体素的形态学方法(VBM)是分析大脑解剖学(结构)差异最常用方法之一, 其通过给大脑volume逐体素打标签(分类)的方式来进行组织分割,过程高度自动化,比传统的基于ROI先验假设的分析方式得到的结果,更加具有稳定性和可重复性。VBM可以定量地测量出脑组织中各组织成分的…

VBM后的双样本t检验

上一篇文章写到做完了VBM&#xff0c;做完后因为数据一般都是患者组和HC组&#xff0c;这两个组之间需要进行比较&#xff0c;那么我们就要进行双样本t检验。 这里介绍双样本t检验的做法。 依然使用的是SPM-fMRI。 1.第一步是选择Specify 2nd-level 打开以后我们可以看到这个界…

VBM后的配对t检验以及xjview使用

之前写了VBM后的双样本t检验&#xff0c;再记录一下配对t检验。 配对t检验和双样本t检验的过程基本一致。包括以下三个步骤。 第一步输入两组被试时&#xff0c;应该成对输入&#xff0c;共有几个被试就有几个pair。 但是这里我在做的过程中没有加协变量&#xff0c;不知道会不…

Visual Basic

目录 一&#xff0c;Visual Basic 二&#xff0c;控制台程序 三&#xff0c;可视化程序 1&#xff0c;IDE 2&#xff0c;实例——加法计算器 一&#xff0c;Visual Basic Visual Basic是可视化的Basic&#xff0c;简称VB VB是第一个可视化编程语言。 二&#xff0c;控制…

VBM法MRI图像处理——记第一次使用cat12

1.环境 MATLAB 2015b SPM12 CAT12 2.SPM部分 命令行输入 spm 出现 以及 点击Toolbox 出现 3.CAT部分 点击上图 设置请根据自己需求 多分割了一种surface皮层数据&#xff0c;当做皮层统计分析SBM时需要提取surface皮层指标时会用到。 我本意只是获得灰质、白质的体积…

VBM_DARTEL算法对灰质变化的计算

根据一些文献得知&#xff0c;VBM目前比较新的算法是DARTEL算法&#xff0c;这一算法被集成在SPM里&#xff0c;这里记录一下做法。 VBM是对T1像进行分割得到灰质等。所以要有结构T1加权像数据。 整个流程应该是这样&#xff1a; 1.手动调整前联合&#xff08;AC&#xff09; …

基于cat12搞定VBM的ROI分析——vertex水平和ROI水平的双样本T检验

前言 本来上周要更新此篇的&#xff0c;但由于本身有问题没有解决清楚&#xff0c;再加上导师给了数据处理的任务下来了&#xff0c;两下耽搁&#xff0c;就等到现在了。上回说到&#xff0c;做了VBM和SBM的指标提取及双样本T检验的统计分析&#xff0c;那接下来我们还可以做什…