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

news2025/1/24 2:28:40

目录

一、数据结构-栈

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) {  
		//构造函数, 空间大小为MaxSize
     	Array = 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.coloradmin.cn/o/1789315.html

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

相关文章

[数据集][目标检测]道路圆石墩检测数据集VOC+YOLO格式461张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;462 标注数量(xml文件个数)&#xff1a;462 标注数量(txt文件个数)&#xff1a;462 标注类别…

node创建项目

前言 &#xff08;一&#xff09;、Web Web的开发体系中&#xff0c;分成前端&#xff0c;后端&#xff0c;工具&#xff0c;三个主要的领域。 前端主要由由浏览器&#xff0c;HTMLCSS浏览器端JS完成。 后端主要是由Web服务器&#xff0c;数据库&#xff0c;动态脚本语言&a…

初识 peerDependencies

目录 初步认识 peerDependencies semver 介绍 # 摘要 # 简介 # 语义化版本控制规范&#xff08;SemVer&#xff09; # 合法语义化版本的巴科斯范式语法 # 为什么要使用语义化的版本控制&#xff1f; # FAQ 示例讲解&#xff1a;vue-router 插件 # 说明 声明 验证 初…

信息系统项目管理师0143:过程概述(9项目范围管理—9.2项目范围管理过程—9.2.1过程概述)

点击查看专栏目录 文章目录 9.2 项目范围管理过程9.2.1 过程概述 9.2 项目范围管理过程 9.2.1 过程概述 项目范围管理过程包括&#xff1a; 规划范围管理&#xff1a;为了记录如何定义、确认和控制项目范围及产品范围&#xff0c;创建范围管理计划。收集需求&#xff1a;为了…

以sqlilabs靶场为例,讲解SQL注入攻击原理【18-24关】

【less-18】 打开时&#xff0c;获取了自己的IP地址。&#xff0c;通过分析源码知道&#xff0c;会将用户的user-agent作为参数记录到数据库中。 提交的是信息有user-Agent、IP、uname信息。 此时可以借助Burp Suite 工具&#xff0c;修改user_agent&#xff0c;实现sql注入。…

小白级教程—安装Ubuntu 20.04 LTS服务器

下载 本教程将使用20.04版进行教学 由于官方速度可能有点慢&#xff0c;可以下方的使用清华镜像下载 https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/ 点击20.24版本 选择 ubuntu-20.04.6-live-server-amd64.iso 新建虚拟机 下载好后 我们使用 VMware 打开它 这里选…

103、python-第三阶段-13-大数据分布式集群运行

hadoop集群 4个多G的数据在集群中用了2.9分钟&#xff0c;如果在一个机器上运行大概需要十几分钟&#xff0c;所以集群速度还是很快的。

sql 查询 不满足 (一个教师编号 的角色 (role =‘2‘or(role=‘1‘and role =‘0‘)) )

sql 查询 不满足 &#xff08;一个教师编号 的角色 &#xff08;role 2’or&#xff08;role1’and role ‘0’&#xff09;&#xff09; &#xff09; 准备 一个 teacher 表 和数据 表 teacher 和数据 -- ---------------------------- -- Table structure for teacher -- …

短期业绩波动较大被券商不予评级,金种子酒背靠华润如何发力?

《港湾商业观察》施子夫 王璐 虽然一季度成功实现了扭亏为盈&#xff0c;但从近些年年报来看&#xff0c;金种子酒&#xff08;600199.SH&#xff09;的业绩压力依然不容小觑。白酒主业萎靡不振时&#xff0c;金种子酒开始了剥离非主营业务。 这些措施能否有利于主业向好&am…

MQ之初识kafka

1. MQ简介 1.1 MQ的诞生背景 以前网络上的计算机&#xff08;或者说不同的进程&#xff09;传递数据&#xff0c;通信都是点对点的&#xff0c;而且要实现相同的协议&#xff08;HTTP、 TCP、WebService&#xff09;。1983 年的时候&#xff0c;有个在 MIT 工作的印度小伙突发…

软理复习范围

1.直觉主义逻辑常采用三值逻辑来处理命题的真值&#xff0c;包括以下三个真值&#xff1a; 真&#xff08;True&#xff09;&#xff1a;表示命题是确定为真的。假&#xff08;False&#xff09;&#xff1a;表示命题是确定为假的。未知&#xff08;Unknown&#xff09;&#…

Keil编译bin格式固件方法

打开Option选项卡&#xff0c;选择User&#xff0c;在After Build/Rebuild下面增加以下命令&#xff1a; fromelf.exe --bin -o "L.bin" "#L"

短剧APP开发,推动短剧市场的全新发展

近几年&#xff0c;短剧火爆出圈&#xff0c;迎来了爆发式增长态势&#xff0c;市场规模一跃达到了百亿元&#xff01;短剧节奏快、剧情爽、情节猎奇&#xff0c;极大地满足了用户的追剧需求&#xff0c;深受大众的喜爱。 短剧巨大的市场发展前景也衍生出了各种新的短剧发展赛…

FSR 3 - Upscaling for Unity(性能优化工具)

FSR 3 - Upscaling for Unity已在Unity版本2021、2022和2023中进行了测试! 使用FSR 3 Upscaling for Unity提升帧数! FSR 3是一种升级技术,它基于较低分辨率的输入创建高质量和高分辨率的帧。通过使用这种方法,您的项目可以在极低的分辨率下运行,而不会损失视觉质量,也不…

连锁实体店同城引流的两种方式

连锁实体店开在哪里&#xff0c;它的影响力就在哪里&#xff0c;所以&#xff0c;连锁店的选址很重要&#xff0c;这点是毋庸置疑的&#xff0c;今天我们聊聊连锁实体店引流的两种方式。 1、同城引流新客到店 实体店的覆盖范围在3-5公里 使用抖音同城引流快速覆盖这个范围内的…

产品经理:做好有效的客户需求分析

需求分析是产品开发过程中的重要环节&#xff0c;它直接决定了产品是否能够满足市场需求和用户期望。通过深入了解客户需求&#xff0c;产品经理可以确保产品功能的设计符合用户的实际需求&#xff0c;从而提高产品的用户满意度和市场竞争力。 一、识别用户需求 识别用户需求…

从头搭hadoop集群--模版虚拟机的配置

软件说明&#xff1a; VMware Workstation Pro MobaXterm_Personal_12.4 映像文件&#xff1a;CentOS-7-x86_64-DVD-1908.iso jdk版本&#xff1a;jdk1.8.0_111 映射文件和jdk文件如下&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/18dsDlLk4WeW2Y8O2jUSkGQ?pw…

微服务学习Day9-分布式事务Seata

文章目录 分布式事务seata引入理论基础CAP定理BASE理论 初识Seata动手实践XA模式AT模式TCC模式SAGA模式 高可用 分布式事务seata 引入 理论基础 CAP定理 BASE理论 初识Seata 动手实践 XA模式 AT模式 TCC模式 Service Slf4j public class AccountTCCServiceImpl implements A…

运维开发介绍

目录 1.什么是运维开发 2.作用 3.优点 4.缺点 5.应用场景 5.1.十个应用场景 5.2.网站和Web应用程序 6.案例 7.小结 1.什么是运维开发 运维开发&#xff08;DevOps&#xff09;是一种结合软件开发&#xff08;Development&#xff09;与信息技术运维&#xff08;Opera…

使用Vue.js将form表单传递到后端

一.form表单 <form submit.prevent"submitForm"></form> form表单像这样写出来&#xff0c;然后把需要用户填写的内容写在form表单内。 二.表单内数据绑定 <div class"input-container"><div style"margin-left: 9px;"&…