数据结构之顺序队列的优化
顺序队列的优化
我们既然想优化顺序队列,首先得知道目前顺序队列的瓶颈在哪里,那样才能对症下药。
顺序队列的瓶颈:
1.线性表的第一个元素作为队头,线性表的最后一个元素作为队尾;
2.入队的新元素是在线性表的最后,时间复杂度为O(1)
3.出队时需要将后续的所有元素向前移动,时间复杂度O(n)
问题:如何将出队操作的时间复杂度降低到O(1)?
顺序队列的优化方案
1.定义front使其始终代表队头的下标,出队时将队头元素返回,且front++;
2.定义rear使其始终代表队尾下一个元素的下标,入队时将新元素插入,且rear++。
没有必要只将下标为0的位置定义为队头!!
队头元素: node[4] 队列长度:6
顺序队列的关键状态:
1.初始状态:length == 0, front == 0, rear == 0;
2.空队列状态:length == 0, front == rear;
3.满队列状态:length == capacity, front == rear;
从关键状态我们发现,队列为空时或者满时都有front = rear,这样就不是很好判断队列的空和满的状态,但是这些都难不倒我们,我们可以通过两种方式来解决这个问题:1.另设一个标志位以区别队列的“空”还是“满”,就比如上面的length;2.少用一个元素空间,约定以“队列头指针在队列尾指针的下一位置上”作为队列呈“满”状态。满队列:front = (rear + 1) % capacity;空队列:front =rear。
循环使用队列中的空间:
1.入队:rear = (rear + 1) % capacity;
2.出队:front = (front + 1) % capacity;
下面我们看一下代码
创建队列
typedef unsigned int TSeqQueueNode;
// 定义一个顺序队列结构体
typedef struct _tag_SeqQueue
{int capacity;int length;int front;int rear;TSeqQueueNode* node;
} TSeqQueue;
// 创建队列
SeqQueue* SeqQueue_Create(int capacity) // O(1)
{TSeqQueue* ret = NULL;// 队列容量合法性OK,为队列申请内存if( capacity >= 0 ){ret = (TSeqQueue*)malloc(sizeof(TSeqQueue) + sizeof(TSeqQueueNode) * capacity);}// 内存申请成功,定义空队列if( ret != NULL ){ret->capacity = capacity;ret->length = 0;ret->front = 0;ret->rear = 0;ret->node = (TSeqQueueNode*)(ret + 1);}return ret;
}
从代码中看出,创建顺序队列和创建顺序表基本相似,就是多了ret->front = 0;和ret->rear = 0。
销毁队列和清空队列:
// 销毁队列
void SeqQueue_Destroy(SeqQueue* queue) // O(1)
{free(queue);
}
// 清空队列
void SeqQueue_Clear(SeqQueue* queue) // O(1)
{TSeqQueue* sQueue = (TSeqQueue*)queue;// 队列合法性检查OKif( sQueue != NULL ){sQueue->length = 0;sQueue->front = 0;sQueue->rear = 0;}
}
还是和操作顺序表基本相似。
进队列代码
// 进队列
int SeqQueue_Append(SeqQueue* queue, void* item) // O(1)
{// 定义顺序表队列变量,强制转换入口参数TSeqQueue* sQueue = (TSeqQueue*)queue;// 入口参数合法性检查int ret = (sQueue != NULL) && (item != NULL);ret = ret && (sQueue->length + 1 <= sQueue->capacity);// 合法性检查OK,插入新元素,尾指针加1,队列长度加1if( ret ){sQueue->node[sQueue->rear] = (TSeqQueueNode)item;sQueue->rear = (sQueue->rear + 1) % sQueue->capacity;sQueue->length++;}return ret;
}
出队列代码
// 出队列
void* SeqQueue_Retrieve(SeqQueue* queue) // O(1)
{// 定义顺序表队列变量,强制转换入口参数TSeqQueue* sQueue = (TSeqQueue*)queue;// 取出队头元素void* ret = SeqQueue_Header(queue);// 取队头元素OK,头指针加1,队列长度减1if( ret != NULL ){sQueue->front = (sQueue->front + 1) % sQueue->capacity;sQueue->length--;}// 返回头元素地址return ret;
}
获取对头元素、队列长度、队列容量
// 获取队头元素
void* SeqQueue_Header(SeqQueue* queue) // O(1)
{// 定义顺序表队列变量,强制转换入口参数TSeqQueue* sQueue = (TSeqQueue*)queue;void* ret = NULL;// 队列合法性检查OK,返回队列头元素地址if( (sQueue != NULL) && (sQueue->length > 0) ){ret = (void*)(sQueue->node[sQueue->front]);}return ret;
}
// 获取队列的长度
int SeqQueue_Length(SeqQueue* queue) // O(1)
{// 定义顺序表队列变量,强制转换入口参数TSeqQueue* sQueue = (TSeqQueue*)queue;int ret = -1;// 队列合法性检查OK,返回队列长度if( sQueue != NULL ){ret = sQueue->length;}return ret;
}
// 获取队列的容量
int SeqQueue_Capacity(SeqQueue* queue) // O(1)
{// 定义顺序表队列变量,强制转换入口参数TSeqQueue* sQueue = (TSeqQueue*)queue;int ret = -1;// 队列合法性检查OK,返回队列容量if( sQueue != NULL ){ret = sQueue->capacity;}return ret;
}
测试代码
#include <stdio.h>
#include <stdlib.h>
#include "SeqQueue.h"/* run this program using the console pauser or add your own getch, system("pause") or input loop */int main(int argc, char *argv[])
{SeqQueue* queue = SeqQueue_Create(6);int a[10] = {0};int i = 0;for(i=0; i<10; i++){a[i] = i + 1;SeqQueue_Append(queue, a + i);}printf("Header: %d\n", *(int*)SeqQueue_Header(queue));printf("Length: %d\n", SeqQueue_Length(queue));printf("Capacity: %d\n", SeqQueue_Capacity(queue));while( SeqQueue_Length(queue) > 0 ){printf("Retrieve: %d\n", *(int*)SeqQueue_Retrieve(queue));}printf("\n");for(i=0; i<10; i++){a[i] = i + 1;SeqQueue_Append(queue, a + i);printf("Retrieve: %d\n", *(int*)SeqQueue_Retrieve(queue));}SeqQueue_Destroy(queue);return 0;
}
到此也就完成了顺序队列的优化,整体代码请点击下方的链接。
顺序队列的优化C实现
数据结构之顺序队列的优化相关推荐
- 数据结构之链式队列的优化
链式队列的优化 上一节我们讲了一下顺序队列的优化,本节我们讲一下链式队列的优化.同理,我们得先知道链式队列的瓶颈在哪里. 链式队列的瓶颈 1.线性表的第一个元素作为队头,线性表的最后一个元素作为队尾: ...
- 【数据结构】顺序队列的实现(C语言)
队列的基本概念及其描述 队列是一种特殊的线性表,它的特殊性在于队列的插入和删除操作分别在表的两端进行. 插入的那一端称为队尾,删除的那一端称为队首.队列的插入操作和删除操作分别称为进队和出队. 先进先 ...
- 数据结构之顺序队列和链式队列常用的一些操作
顺序队列是队列的顺序存储结构,顺序队列实际上是运算受限的顺序表.和顺序表一样,顺序队列用一个向量空间来存放当前队列中的元素.由于队列的队头和队尾的位置是变化的,设置两个指针front和rear分别指示 ...
- (c语言数据结构)用顺序队列的方式实现输入12345,输出12345操作——期末数据结构程序设计
用顺序队列的方式实现输入123456,输出12345操作 文章目录 用顺序队列的方式实现输入123456,输出12345操作 1.队列的定义 2.队列的初始化 3.判空操作 4.入队操作 5. 出队操 ...
- 浅谈数据结构之顺序队列(五)
队列:是指只允许在一端进行插入操作,而在另一端进行删除操作的线性表.队列是一种先进先出的线性表,这与栈的后进先出正好相反:其中允许插入的一端我们称为队尾,允许删除的一端我们称为队头(或队首).假设队列 ...
- 数据结构(二):线性表包括顺序存储结构(顺序表、顺序队列和顺序栈)和链式存储结构(链表、链队列和链栈)...
还记得数据结构这个经典的分类图吧: 今天主要关注一下线性表. 什么是线性表 线性表的划分是从数据的逻辑结构上进行的.线性指的是在数据的逻辑结构上是线性的.即在数据元素的非空有限集中 (1) 存在唯一的 ...
- 【数据结构】队列-顺序队列、循环队列、链队、双端队列
定义 队列是只允许在一端进行插入,而在另一端进行删除的线性表. 队头(Front):允许删除的一端,又称为队首. 队尾(Rear): 允许插入的一端. 先进入队列的元素必然先离开队列,即先进先出(Fi ...
- 数据结构 队列(顺序队列 循环队列 链队列)
目录 一.引入 二.队列的定义 三.队列的抽象数据类型 四.队列的存储方式 五.队列的顺序存储(不太常用 后面5.4会给出原因) 5.1顺序存储队列的基本知识点 5.2队列的顺序存储描述 5.3顺序存 ...
- 数据结构与算法(3-2)队列(顺序队列、循环队列与链队列)
目录 一.顺序队列 1.存储结构 2.入队和出队 总代码 二.循环队列 总代码: 三.链队列 1.存储结构 2.入队和出队 总代码 一.顺序队列 队列特征:先进后出.后进后出. 1.存储结构 //队列 ...
最新文章
- 盘点:2020 年机器学习 10 大进展
- 3、spring注解注入
- java用redis缓存的步骤_详解在Java程序中运用Redis缓存对象的方法|chu
- 如何修改浏览器的默认滚动条样式
- 最新 Unity3D鼠标滑轮控制物体放大缩小 [
- 苹果笔记本单独安装win10
- canvas转化为图片并下载
- Linux-shell获取天气
- python中执行shell命令_python中执行shell命令的几个方法小结-阿里云开发者社区
- DeepMind为明年的AAAI,准备了一份各种DQN的混血
- RAR Extractor Max for Mac(解压缩软件)
- Gut Microbes:南医大刘星吟组-孤独症的基因变异与肠道微生物群、代谢物和细胞因子的改变有关...
- uploadify3.1 php,Jquery上传插件 uploadify v3.1使用说明_jquery
- Axure RP 8 获取焦点的应用
- 用qt 编译qt moc
- 把撒哈拉沙漠变成一个太阳能农场,这可能吗?
- java chmod 777_尽管使用chmod 777,但java.io.FileNotFoundException(权限被拒绝)
- 苹果手机怎样录屏 如何录制手机内容
- filter_input
- IT大佬告诉你大数据有哪些特点,新人学习必知
热门文章
- python自定义assert抛出的异常
- Linux定时向目标服务器传输文件
- linux5.5 分辨率,Linux Kernel 5.5 正式发布
- java http zip参数,如何从Web API 2 HttpGet发送zip文件
- rust最低什么显卡能游戏_腐蚀Rust配置要求汇总 腐蚀Rust游戏配置要求是什么_游侠网...
- 【thinkphp】ThinkPHP各个低版本(=3.2)完全配置参考手册
- 【设计模式】适配器模式 Adapter Pattern
- 龙应台--为什么我要求你读书用功
- Maven--部署构件至 Nexus
- java第一次作业计科2班马浩加