【第三节】C/C++数据结构之栈与队列

目录

一、数据结构-栈

1.1 栈的定义

1.2 栈的 ADT (Abstract Data Type)

1.3 栈的顺序存储结构及实现

二、数据结构-队列

2.1 队列的定义

2.2 队列的 ADT

2.3 队列的顺序存储结构与实现

2.4 优先队列

2.5 各种队列异同点


一、数据结构-栈

1.1 栈的定义

栈(Stack)可以看成是一种特殊的线性表。

限定仅只能在表尾端进行插入和删除的线性表。
栈顶:表尾端被称之为栈顶。
栈底:和表尾相对应的另一端,称之为栈底。
时间有序表:LIFO (Last In First Out)后进先出特征的线性结构。

1e674f57d5df4273ae768853d2156b11.png

1.2 栈的 ADT (Abstract Data Type)

template <class ElemType> 
class AbsStack {public:AbsStack ( ) { }		  // 默认构造函数virtual ~ AbsStack ( ) {  } 	  // 析构函数virtual int IsEmpty ( ) const = 0;   // 判栈空吗?virtual int IsFull ( ) const = 0;      // 判栈满吗?virtual void MakeEmpty( ) = 0;    //将栈清空。virtual void Push ( const ElemType & X ) = 0;  //新结点进栈。virtual void Pop (  ) =  0;  // 栈顶结点出栈。virtual const ElemType & Top( ) const = 0;  // 取栈顶结点数据值。private:AbsStack( const AbsStack & ) {  } // 冻结复制另一堆栈的构造函数。
}; 

1.3 栈的顺序存储结构及实现

与线性表类似,栈也有两种存储结构,即顺序存储和链表存储结构。
栈的顺序存储结构亦称顺序栈。
栈的顺序存储结构是利用一批地址连续的存储单元依次存放自栈底到栈顶的数据元素,同时设指针 top 指向栈顶元素的当前位置。
通常用一维数组来实现栈的顺栈存储,习惯上以数组下标小的一端做栈底,当top=0时为空栈。数据元素不断进栈时,栈顶指针top不断地加1,当top达到数组的最大下标值时为栈满。

dd66707323184d4087d01a6c12471936.png

顺序表示的栈的程序实现:

static const int InitStackSize = 10;
template <class ElemType> class Stack: public AbsStack<ElemType>  {
private:ElemType * Array;       //  存放结点的数组名。int top;	         //  top - 栈顶指针。int MaxSize;     //  栈内能够存放结点的最大个数,即栈的容量。void DoubleArray( int Max );	 // 更新数组的容量。public:Stack ( );             // 构造函数, 初始时构造大小为InitStackSize的栈。~Stack ( ) { delete [ ] Array; };	// 析构函数,释放占用的连续空间。void MakeEmpty ( ) { top = -1; };  // 将栈清空。int IsEmpty ( ) const { return top = = -1; };     //栈空为True,否则为False。int IsFull ( ) const { return top = = MaxSize-1; }; //栈满为True,否则为False。const ElemType & Top( ) const ;              // 读取栈顶结点。void Push ( const ElemType & X );    	        // 将X的值进栈。void Pop ( );                   		   // 栈顶结点出栈。const Stack & operator = ( const Stack & R );
};template<class ElemType> 
Stack<ElemType> :: Stack( ) : top( -1), MaxSize(InitStackSize) {  //构造函数, 空间大小为MaxSizeArray = new ElemType[MaxSize];
}
template <class ElemType> const ElemType & Stack<ElemType> :: Top( ) const {// 对非空栈,读取栈顶结点并返回结点的值。Exception( IsEmpty( ),  ”Underflow:Satck is Empty!”);return Array[top];  
}
template <class ElemType> void Stack<ElemType>::Push ( const ElemType & X ) {   if  ( top + 1 = = MaxSize )	DoubleArray( 2 * MaxSize );Array[++top] = X;      	// 新结点放入新的栈顶位置。
}
template <class ElemType> void Stack<ElemType>::Pop() { //对非空栈,将栈顶结点出栈Exception( IsEmpty( ),  ”Stack is underflow!”);top--;	   
}template <class ElemType> 
const Stack<ElemType> & Stack<ElemType> :: operator = ( const Stack<ElemType> & R 						) {   if ( this = = &R )  return *this; delete [ ]Array; Array = new ElemType[R.MaxSize];   // 分配存储单元。top = R.top;  for( int j=0; j<= top; j++ )  Array[j] = R.Array[j];  // 逐个复制结点。return *this;
}
template <class ElemType> 
void  Stack<ElemType> :: DoubleArray( int Max ) {   ElemType * oldarr = Array;Exception( MaxSize≥Max, “New size is too small!”);Array = new ElemType[Max];for( int k = 0; k <= top; k++ ) Array[k] = oldarr[k]; 	// 逐个复制结点。MaxSize = Max;delete [ ] oldarr;return;
}

多栈共享一块顺序存储空间:栈顶指针指向实际栈顶的下一个单元。

5a8cefa60a10466ea4332701841d47a5.png

二个栈共享一块顺序存储空间:栈顶指针指向实际栈顶的下一个单元。指针相遇时,栈满。

7c12f37597ba4576aa4e1b7aa4e62d20.png

top 是栈顶指针。栈顶和栈底如图所示。

4faf281ea543483d8befaa5b2add298f.png

栈的 Push 操作:

4b06ab11f033470d9ff8b56b588ca236.png

6b64793c5e5443ab9104096710c8fe5f.png

栈的 Pop 操作:

790e5c83528545efa89c8a2c4220bce5.png

8050062353214a6ba8714d5127d4401d.png

二、数据结构-队列

2.1 队列的定义

队列(Queue)也是一种特殊的线性表。在现实中例子很多,如客户到银行办理业务往往需要排队,先来的先办理,晚来的则排在队尾等待。队列也有两种存储结构,即顺序存储和链表存储结构。下面主要讲顺序存储的实现。

在表的一端进行插入,而在另一端进行删除的线性表。
队尾:进行插入的一端。
队首:进行删除的一端。
时间有序表:FIFO (先进先出)特征的线性结构。

2.2 队列的 ADT

template <class ElemType>   class AbsQueue {
public:AbsQueue ( ) { } 		  // 默认构造函数virtual ~ AbsQueue ( ) {  } 	  // 析构函数virtual int IsEmpty ( ) const = 0;  // 判队空吗?virtual int IsFull ( ) const = 0;    // 判队满吗?virtual void MakeEmpty( ) = 0;  //将队清空。virtual void EnQueue( const ElemType & X ) = 0;  //新结点进队。virtual void DeQueue( ) =  0;    // 队首结点出队。virtual const ElemType & Front( ) const = 0;  // 取队首结点数据值。
private:AbsQueue ( const AbsQueue & ) {  } // 冻结复制另一队列的构造函数。};

2.3 队列的顺序存储结构与实现

队列的表示

2e44941f9c744d11870aae4a87d464af.png

df63c904644443d7b497d136268c99a4.png

f6cfd49d044947058c1e51dbaf8ec967.png

出队时应先判队是否空:条件  rear == front
不空则出队,注意 front 是否会由最高下标跳至最低下标(循环)。


 进队时应先判队是否满:条件  ( ( rear + 1) % maxSize ) == front

不满则进队,注意 rear 是否会由最高下标跳至最低下标(循环)。

基本操作的实现程序:进队。

template <class ElemType>void Queue<ElemType>::EnQueue(const ElemType & x) {// 值为x的结点进队。if ( IsFull( ) )  DoubleQueue( );   Array[rear] = x; // 若队满,则数组容量扩大一倍。Increment( rear);    // rear 加 1;若为 MaxSize,则rear取0。 
}
int IsFull( ) const {return ( rear + 1) % MaxSize = = front ; }	

8fbf14c183514035be714b352394d286.png

基本操作进队的实现程序:扩大数组容量

template <class ElemType>void Queue<ElemType>::EnQueue(const ElemType & x) {// 值为x的结点进队。if ( IsFull( ) )  DoubleQueue( );   Array[rear] = x;Increment( rear);
}template <class ElemType>
int IsFull( ) const {return ( rear + 1) % MaxSize = = front ; }	template <class ElemType> 
void Queue<ElemType>::DoubleQueue( )  {//重新创建数组单元个数多一倍的新数组,复制原队列中的结点。int NewSize = 2 * MaxSize; ElemType * old = Array;Array = new ElemType[NewSize];for ( int j = 0, k = front; k < rear; j++, Increment(k) ) Array[j] = old[k];front = 0;    // 新的队首指针。rear = j;  // 新的队尾指针。MaxSize = NewSize;  delete [ ]old; 
}

基本操作出队的实现程序:

template <class ElemType> void Queue<ElemType>::DeQueue( )  {//对于非空队列,将队首结点出队。Exception( IsEmpty( ),  ”Queue is underflow!”);Increment( front ); 
}
int IsEmpty() const {return front = = rear;}	//判断队列是否空.。为空返回True,否则返回False。

dc6f46763b314c5e87964c4490ba49f4.png

求队中结点的个数:( rear - front + MaxSize ) % MaxSize

front 和 rear 分别是队首和队尾指针。它们指示着真正的队首和真正的队尾结点。

6dff2b07e09249fc872ced16df7b5b0d.png

70b3b26d17c74184b9cd82e5a2b0032e.png

template <class ElemType> class Queue : public AbsQueue<ElemType>  {private:ListNode<ElemType> * front;	       //  队首指针。ListNode<ElemType> * rear;	       //  队尾指针。public:Queue ( ) : front(NULL), rear(NULL) { } // 构造函数: 队首指针和队尾指针初始化。~Queue ( ) { MakeEmpty( ); }	//析构函数,释放占用的连续空间。void MakeEmpty ( ); 		 // 将队列清空。int IsEmpty ( ) const { return front = = NULL; }  // 队空为True,否则为False。int IsFull ( ) const { return 0; } 	  // 总认为为False。const ElemType & Front ( ) const ; // 读取队首结点数据值。void EnQueue ( const ElemType & X );    // 将X的值进队。void DeQueue ( );                   		// 将队首结点出队。const Queue & operator = ( const Queue & R );};

进队操作:

template <class ElemType> 
void Queue<ElemType>::EnQueue ( const ElemType & X ) {   if ( IsEmpty( ) )  front = rear= new ListNode <ElemType> ( X );else rear = rear->Next = new ListNode<ElemType> ( X );
}

c6db1f460b1547c7b58aa5d18b05e539.png

2.4 优先队列

优先权有序表:具有特征高优先权的结点将先离开的线性结构。和到达时刻无关。
实现方法:结点中处包含数据场外,还有本结点的优先权数。优先权数越小(如本书) ,优先级越高。或者优先权数越大,优先级越高。
顺序存储的优先队列:用数组

9a74669faed749bf92d60ddc21d08921.png

2.5 各种队列异同点

数据结构中普通队列、循环队列和优先队列的异同点如下:

相同点

  1. 先进先出原则:普通队列和循环队列都遵循先进先出(FIFO)的原则,即最早进入队列的元素将最早被移除。优先队列虽然也遵循某种顺序,但其核心特点不在于FIFO,而是根据元素的优先级来决定出队的顺序。

  2. 基本操作:这些队列类型都支持基本的入队(在队列尾部添加元素)和出队(从队列头部移除元素)操作。

不同点

  1. 存储和循环使用

    • 普通队列:使用数组或链表来存储元素,当元素被移除后,其空间不会被再次利用,可能导致空间浪费。
    • 循环队列:通过逻辑上首尾相连的方式实现队列空间的循环利用,提高了存储空间的利用率。循环队列需要额外的机制来判断队列是满还是空1。
    • 优先队列:与普通队列和循环队列在存储空间使用上的主要区别在于其出队顺序。优先队列根据元素的优先级进行出队,而不是按照FIFO的原则。
  2. 出队顺序

    • 普通队列循环队列:按照元素进入队列的顺序进行出队。
    • 优先队列:出队顺序基于元素的优先级,优先级高的元素先出队2。
  3. 应用场景

    • 普通队列循环队列:常用于需要按照特定顺序处理元素的场景,如操作系统中的进程调度、广度优先搜索等3。
    • 优先队列:特别适用于需要根据优先级处理元素的场景,如任务调度、图像处理中的优先级渲染等34。
  4. 实现和性能

    • 普通队列循环队列:实现相对简单,性能稳定。循环队列在减少内存分配和释放的开销方面可能更优。
    • 优先队列:实现通常基于堆数据结构(如最大堆或最小堆),因此具有不同的性能特点。插入和删除元素的时间复杂度通常为O(logN)2。

总结来说,普通队列和循环队列主要在存储空间的利用和循环使用上有所不同,而优先队列则主要在元素的出队顺序和实现机制上与其他两种队列有所区别。这些队列类型各自适用于不同的应用场景和需求。

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

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

相关文章

租赁小程序基于ThinkPHP+FastAdmin+UniApp

本文来自&#xff1a;XYlease租赁小程序基于ThinkPHPFastAdminUniApp - 源码1688 应用介绍 基于ThinkPHPFastAdminUniApp开发的租赁商城小程序&#xff0c;提供用户物品租赁服务的应用程序&#xff0c;方便客户搭建各种类型的租赁场景服务。通过小程序端多角色进行平台管理&…

SpringBoot修真秘籍

一、古代篇 在修仙界中&#xff0c;Spring Boot 自动装配之术&#xff0c;犹如炼器炉中的异火&#xff0c;能够将繁杂的配置化作一缕轻烟&#xff0c;让修仙者在构建应用之路上&#xff0c;如履平地&#xff0c;轻松驾驭。 第一章&#xff1a;灵根觉醒——Spring Boot 的诞生 …

【方法论】钟澄国家杰青 鲸吞法 写文献综述、大论文框架必备

Xlab2020的个人空间-Xlab2020个人主页-哔哩哔哩视频 老师指南 就是1号文件有了后&#xff0c;也就是【】概括了之后&#xff0c;我们会运行下程序&#xff08;程序我会让学生share&#xff09;。然后程序会执行这么一个操作&#xff0c;复制下【】内容&#xff0c;然后在第二个…

SpringBoot: 使用GraalVM编译native应用

曾今Go语言里让我最艳羡的两个特性&#xff0c;一个是Goroutine&#xff0c;一个是native编译。 Java 21的虚线程实现了类似Goroutine的能力。Spring Boot 3.x开始提供了GraalVM的支持&#xff0c;现在Spring Boot也能打包成native文件了。 这一篇文章的目标是用一个案例讲解如…

pidstat -d 1分析磁盘吞吐量

iostat -dx 1 查看磁盘IO吞吐量 pidstat -d 1看是哪个进程写的

水电站大坝安全监测工作详解

水电站大坝安全监测是确保大坝结构安全和操作安全的关键组成部分。本文将详细解释水电站大坝安全监测的9项主要工作内容&#xff0c;帮助理解其重要性和执行过程。 1) 现场监测 现场监测是水电站大坝安全监测的首要步骤。监测人员需要定期对大坝的物理结构进行检查&#xff0c;…

论文AI率不达标?AI工具助你一臂之力

告诉大家一个非常残忍的答案&#xff0c;以后所有论文都会被查ai率的。 学术界不仅关注传统的抄袭问题&#xff0c;还增加了一项名为“AIGC检测”的指标。例如知网、维普等平台都能检测论文AI率。 用GPT写论文虽然重复率基本不用担心&#xff0c;但是AI率基本都较高&#xff…

在 Qt Creator 上创建 ROS 项目并新建/导入 ROS 包

0、引言 ⚠️ 在开始之前&#xff0c;您需要确保您已经为 Qt 配置好了 ROS 开发环境了。如果您还没有配置好&#xff0c;可以参考这篇文章 本文将着手探讨如何在 Qt Creator 上编辑 ROS 项目&#xff08;工作空间&#xff09;。 1、本教程使用到的相关软件或产品 Ubuntu 20.0…

OpenCV学习(4.2) 图像的几何变换

1.目标 学习将不同的几何变换应用到图像上&#xff0c;如平移、旋转、仿射变换等。你会看到这些函数: cv.getPerspectiveTransform 2.缩放 缩放是调整图片的大小。 OpenCV 使用 cv.resize() 函数进行调整。可以手动指定图像的大小&#xff0c;也可以指定比例因子。可以使用不…

【Vue】小黑记事本

文章目录 一、需求说明二、思路分析三、代码实现 一、需求说明 拆分基础组件渲染待办任务添加任务删除任务底部合计 和 清空功能持久化存储 二、思路分析 拆分基础组件 咱们可以把小黑记事本原有的结构拆成三部分内容&#xff1a;头部&#xff08;TodoHeader&#xff09;、列…

基于semantic_kernel的ChatMD系统

问答系统需求文档 一、项目概述 本项目旨在开发一个能够上传 MD 文件&#xff0c;并基于 MD内容进行问答互动的系统。用户可以上传 MD文件&#xff0c;系统将解析 MD内容&#xff0c;并允许用户通过对话框进行问答互动&#xff0c;获取有关 MD文件内容的信息。 二、功能需求…

保研面试408复习 8——计算机网络(浏览器http)、离散数学(平面图)、操作系统、数据结构

文章目录 一、计算机网络1、从在浏览器输入网址到页面显示的过程1. 输入网址2. DNS 解析3. 建立TCP连接4. 发送HTTP请求5. 服务器处理请求并响应6. 浏览器处理响应7. 页面渲染 二、离散数学一、平面图1、平面图性质2、Kuratowski定理 三、操作系统四、数据结构 一、计算机网络 …

IDCF五周年专场—【研发效能·创享大会】圆满落幕!

2024 年5 月25 日&#xff0c;【研发效能创享大会】—IDCF五周年专场在北京希尔顿欢朋酒店&#xff08;大红门&#xff09;成功举办&#xff01;本次大会旨在为社区成员提供一个学习与交流的平台&#xff0c;分享技术经验&#xff0c;交流行业见解&#xff0c;促进技术合作与创…

【Java基础】线程的五大状态

新建状态 使用 new 关键字和 Thread 类或其子类建立一个线程对象后&#xff0c;该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。 就绪状态 当线程对象调用了start()方法之后&#xff0c;该线程就进入就绪状态。就绪状态的线程处于就绪队列中&#xff…

景深技术在AI绘画中的魔法:为数字艺术注入新维度

引言&#xff1a; 在人工智能&#xff08;AI&#xff09;的浪潮中&#xff0c;绘画艺术领域迎来了革命性的变革。AI绘画不仅改变了创作过程&#xff0c;还为艺术家和设计师提供了前所未有的工具。其中&#xff0c;景深技术作为一种重要的视觉处理手段&#xff0c;在AI绘画中的应…

告别繁琐,Xinstall一键解决App代理结算难题!

在移动互联网的浪潮中&#xff0c;App的推广和运营成为了众多企业和开发者关注的焦点。然而&#xff0c;随着App市场的日益竞争&#xff0c;代理结算的复杂性和繁琐性成为了许多推广者头疼的问题。为了解决这个问题&#xff0c;Xinstall凭借其专业的技术和丰富的服务经验&#…

Modebus通信协议 温控器示例

目录 1 指令解释 2 获取动态的CRC 3 crc在线验证 4 16进制正负温度互转 4.2 16进制转温度 4.2 温度转16进制 5 完整工具类 最近安卓工作接了很多硬件&#xff0c;其他的都是发个固定指令&#xff0c;比较有代表性就是温控器和打印机自定义内容所以这个记录接入示例&…

为什么没有输出九九乘法表?

下面的程序本来想输出九九乘法表到屏幕上&#xff0c;为什么没有输出呢&#xff1f;怎样修改&#xff1f; <!DOCTYPE html> <html> <head> <meta charset"utf-8" /> <title>我的HTML练习</title> …

新火种AI|倒反天罡!美国名校斯坦福AI团队抄袭中国大模型

作者&#xff1a;一号 编辑&#xff1a;美美 中国大模型被抄袭&#xff0c;怎么不算是某种层面上的国际认可呢&#xff1f; 5月29日&#xff0c;斯坦福大学的一个AI研究团队发布了一个名为「Llama3V」的模型&#xff0c;号称只要 500 美元就能训练出一个 SOTA 多模态模型&am…

知识库系统:从认识到搭建

在这个信息过载的时代&#xff0c;企业越来越需要一个集中的知识库系统来促进员工协作和解决问题。本文跟着LookLook同学一起来探讨搭建高效知识库系统的所有注意事项和知识库系统的最佳推荐。 | 什么是知识库系统 知识库系统是一种软件或工具&#xff0c;旨在填补组织内的知识…