参考链接:数据结构探险—队列篇

数据结构太重要了,不学好是没法进行软件开发的。

C++写数据结构基本套路:一个.h文件写该数据结构类的接口;一个.cpp文件写接口的具体实现;一个main.cpp用于测试。

队列


队列的模型

想象一下现实生活中的队列,排队先入先出,不允许插队,队头先出,队尾进入。(应用:营业厅自动排号机)

队列的编程实现方式

环形队列,数组实现,静态的,事先确定队列容量,人为取余,循环利用数组资源。

普通队列,链表实现,动态的,有点浪费,因为插入删除只在队列头尾进行

队列的基本元素

要操纵队列,必须要有一个数组(指针),队列长度,队列容量;然后用队列头和队列尾操纵队列。

环形队列中队列头和队列尾到底意味着什么?对尾指向最后一个元素的下一个位置。

队列的基本操作

创建队列,销毁队列,清空队列,队列判空,队列判满,队列长度;元素入队,元素出对,遍历队列

基本操作的实现

创建队列:构造函数实现,函数参数为队列容量;此步需要完成的任务:形成数组实体,即分配内存,将一些队列基本元素初始化。

销毁队列:析构函数实现,释放内存,指针置空。

清空队列:指针不动,基本元素初始化

队列判空:通过长度判断

队列判满:通过长度和容量判断

队列长度:直接返回

元素入队:判断能否插入,能则插入,更新队列基本信息(技巧)

元素出对:判断是否有东西可以删除,更新队列基本信息

遍历队列:循环,从头到尾,遍历(输出)

大部分的操作都是针对队列基本元素的,会利用和改变它。(所以用C++其实是简化了,只需考虑类内数据元素)

写一个大型的数据结构很难,很容易就会出现某些细小的错误,如果无法控制这些细小的错误,那等程序大起来之后,就很难很难找错和调试了。

C++实现步骤

  • 首先,把上面的流程走一遍,做到心中有数。
  • 设计队列的接口(建议写在一个单独文档里,以便随时查阅),先不谈具体实现;(照着抄很容易,关键要会默写)
  • 实现,核心功能,创建,插入,删除,遍历显示,调试成功
  • 补充其他核心功能

代码要写好,还真是太难了,首先要正确的命名,其次大小写还不能搞错,在使用的时候还要一一对应。

函数的返回值、函数名、参数等等,都不允许有错误。(很难一次性写好,在实现时慢慢修正)

初次亲手敲代码的体会:队列的代码量确实很少,接口20多行;实现80多行,测试20多行,根本就不算多;但是写起来还是感觉很难,之前敲书本上的单个例题,感觉还没什么难度;队列元素太多,基本的5个元素,操作太多,9个基本操作,操作之间部分依赖;我对C++的语法也不算太熟悉,有些卡顿;东西太多,太杂,名称太长,导致我眼花缭乱。

课程笔记

这是之前C++的进阶课,数据结构:一群数据以及数据之间的关系(集合+关系),数据结构是前人经验的总结,所以你学习借鉴就好了,不要钻牛角尖。

队列是先入先出的数学模型,队列中很少用到位序,因为只能对首尾进行操作,载入元素默认实在队尾,删除元素默认是在队头。

队列分为普通队列和环形队列

普通队列:分两种情况,一是队头离开,后面全部前移;二是队头离开,不移,往后继续排,这两种结果都不好

环形队列:充分利用资源,也不牺牲效率;队头队尾重叠只有两种情况,要么为空,要么为满。

队列的C和C++实现方式是大为不同的

在C++中,队列被写成了类,每一个具体队列都是该类的实例;而C语言中,只是简单定义了个结构体,C语言函数的参数中一定要含有队列的地址,而C++因为写在了类中,则不用传参数。

标准C++代码

#pragma once
//MyQueue.h
//环形队列C++实现
class MyQueue
{
public:
MyQueue(int queueCapacity); //InitQueue(&Q)创建队列
virtual ~MyQueue(); //DestroyQueue(&Q)销毁队列
void ClearQueue(); //ClearQueue(&Q)清空队列
bool QueueEmpty() const; //QueueEmpty(&Q)判空队列
int QueueLength() const; //QueueLength(Q)队列长度
bool QueueFull() const; bool EnQueue(int element); //EnQueue(&Q, element)新元素入队
bool DeQueue(int &element); //DeQueue(&Q, &element)首元素出队
void QueueTraverse(); //QueueTraverse(Q, visit())遍历队列
private:
int *m_pQueue; //队列数组数组
int m_iQueueLen; //队列元素个数
int m_iQueueCapacity; //队列数组容量 int m_iHead;
int m_iTail;
};
//MyQueue.cpp
#include"MyQueue.h"
#include<iostream>
using namespace std; MyQueue::MyQueue(int queueCapacity)
{
m_iQueueCapacity = queueCapacity;
m_iHead = 0;
m_iTail = 0;
m_iQueueLen = 0;
m_pQueue = new int[m_iQueueCapacity];
} MyQueue::~MyQueue()
{
delete[]m_pQueue;
m_pQueue = nullptr;
} void MyQueue::ClearQueue()
{
m_iHead = 0;
m_iTail = 0;
m_iQueueLen = 0;
} bool MyQueue::QueueEmpty() const
{
if (m_iQueueLen == 0)
return true;
else
return false;
} bool MyQueue::QueueFull() const
{
if (m_iQueueLen == m_iQueueCapacity)
return true;
else
return false;
} int MyQueue::QueueLength() const
{
return m_iQueueLen;
} bool MyQueue::EnQueue(int element)
{
if (QueueFull())
return false;
else
{
m_pQueue[m_iTail] = element;
m_iTail++;
m_iTail = m_iTail % m_iQueueCapacity;
m_iQueueLen++;
return true;
}
} bool MyQueue::DeQueue(int &element)
{
if (QueueEmpty())
return false;
else
{
element = m_pQueue[m_iHead];
m_iHead++;
m_iHead = m_iHead % m_iQueueCapacity;
m_iQueueLen--;
return true;
}
} void MyQueue::QueueTraverse()
{
for (int i = m_iHead; i < m_iQueueLen + m_iHead; i++)
{
cout << m_pQueue[i%m_iQueueCapacity] << endl;
}
}
//demo.cpp
#include<iostream>
#include"MyQueue.h"
using namespace std; int main()
{
MyQueue *p = new MyQueue(4);
p->EnQueue(1);
p->EnQueue(0);
p->EnQueue(11);
p->QueueTraverse();
p->ClearQueue();
cout << "after clear: " << endl;
p->QueueTraverse();
if (p->QueueEmpty())
cout << "Empty queue" << endl;
else
cout << "Not Empty" << endl;
p->EnQueue(5);
p->EnQueue(15);
p->EnQueue(25);
cout << p->QueueLength() << endl;
int tmp;
p->DeQueue(tmp);
cout << "tmp is " << tmp << endl;
cout << p->QueueLength() << endl;
return 0;
}

 

实际应用

节点的数据可以是任意类型的数据,ElemType为Customer

//Customer.h
#pragma once
#include <string>
using namespace std; class Customer
{
public:
Customer(string name = "", int age = 0);
void printInfo() const;
private:
string m_strName;
int m_iAge;
};
//Customer.cpp
#include<iostream>
#include"Customer.h"
using namespace std; Customer::Customer(string name, int age)
{
m_strName = name;
m_iAge = age;
} void Customer::printInfo() const
{
cout << "Name: " << m_strName << endl;
cout << "Age: " << m_iAge << endl;
cout << "=================" << endl;
}
//demo.cpp
#include<iostream>
#include"MyQueue.h"
using namespace std; int main()
{
MyQueue *p = new MyQueue(4);
Customer c1("zhangsan", 20);
Customer c2("lisi", 30);
Customer c3("wangwu", 24); p->EnQueue(c1);
p->EnQueue(c2);
p->EnQueue(c3); p->QueueTraverse(); cout << endl;
Customer c4;
p->DeQueue(c4);
cout << "this is c4: " << endl;
c4.printInfo(); cout << "this is QueueTraverse: " << endl;
p->QueueTraverse();
return 0;
}

 

使用C++模板写一个队列

 

比较C和C++实现的不同

队列 - 从零开始实现by C++的更多相关文章

  1. 从零开始写STL—栈和队列

    从零开始写STL-栈和队列 适配器模式 意图:将一个类的接口转换成客户希望的另外一个接口.适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 主要解决:主要解决在软件系统中,常常要将 ...

  2. 从零开始写STL-容器-双端队列

    从零开始写STL-容器-双端队列 什么是双端队列?在介绍vector源码,我们发现在vector前端插入元素往往会引起大量元素的重新分配,双端队列(deque)就是为了解决这一问题,双端队列中在首端和 ...

  3. 【MQ】java 从零开始实现消息队列 mq-02-如何实现生产者调用消费者?

    前景回顾 上一节我们学习了如何实现基于 netty 客服端和服务端的启动. [mq]从零开始实现 mq-01-生产者.消费者启动 [mq]java 从零开始实现消息队列 mq-02-如何实现生产者调用 ...

  4. 从零开始实现lmax-Disruptor队列(二)多消费者、消费者组间消费依赖原理解析

    MyDisruptor V2版本介绍 在v1版本的MyDisruptor实现单生产者.单消费者功能后.按照计划,v2版本的MyDisruptor需要支持多消费者和允许设置消费者组间的依赖关系. 由于该 ...

  5. 从零开始实现lmax-Disruptor队列(三)多线程消费者WorkerPool原理解析

    MyDisruptor V3版本介绍 在v2版本的MyDisruptor实现多消费者.消费者组间依赖功能后.按照计划,v3版本的MyDisruptor需要支持多线程消费者的功能. 由于该文属于系列博客 ...

  6. 从零开始实现lmax-Disruptor队列(四)多线程生产者MultiProducerSequencer原理解析

    MyDisruptor V4版本介绍 在v3版本的MyDisruptor实现多线程消费者后.按照计划,v4版本的MyDisruptor需要支持线程安全的多线程生产者功能. 由于该文属于系列博客的一部分 ...

  7. 从零开始实现lmax-Disruptor队列(五)Disruptor DSL风格API原理解析

    MyDisruptor V5版本介绍 在v4版本的MyDisruptor实现多线程生产者后.按照计划,v5版本的MyDisruptor需要支持更便于用户使用的DSL风格的API. 由于该文属于系列博客 ...

  8. 从零开始实现lmax-Disruptor队列(六)Disruptor 解决伪共享、消费者优雅停止实现原理解析

    MyDisruptor V6版本介绍 在v5版本的MyDisruptor实现DSL风格的API后.按照计划,v6版本的MyDisruptor作为最后一个版本,需要对MyDisruptor进行最终的一些 ...

  9. 从零开始实现lmax-Disruptor队列(一)RingBuffer与单生产者、单消费者工作原理解析

    1.lmax-Disruptor队列介绍 disruptor是英国著名的金融交易所lmax旗下技术团队开发的一款java实现的高性能内存队列框架 其发明disruptor的主要目的是为了改进传统的内存 ...

随机推荐

  1. 造字工房情书体MFQingShu_Noncommercial-Regular

    造字工房情书体由造字工房字体设计师成瑜历时半年书写完成,其字形俊秀.遒劲有力,优雅中透出知性的气息.文从字顺,字形笔画柔美俊秀.刚柔并济,结构自然洒脱,充满活力朝气的青春气息,完美呈现了手写汉字之美, ...

  2. 如何用Pr完成作业~

    要求~ 我的工具~(随便搞搞就好了,自己的录音还没弄~)

  3. SqlSever基础 datepart 获取一个日期的月份

    镇场诗:---大梦谁觉,水月中建博客.百千磨难,才知世事无常.---今持佛语,技术无量愿学.愿尽所学,铸一良心博客.------------------------------------------ ...

  4. Cheatsheet: 2014 02.01 ~ 02.28

    Database Managing disk space in MongoDB When to use GridFS on MongoDB .NET The Past, Present, and Fu ...

  5. Freebie: Date Picker Calendar Demo Form For Oracle Forms 6i

    I have already posted and provided the required PLSQL Library and the Calendar FMX file in my previo ...

  6. web后门top

    看到了一个博客  觉得关键点很有用 1)出现频率最高的DDoS后门文件名 abc.php, xl.php, Xml.php, dedetag.class.php, counti.php, plase. ...

  7. CA*Layer(CAShapeLayer--CATextLayer)

    CAShapeLayer CAShapeLayer是一个通过矢量图形而不是bitmap来绘制的图层子类.你指定诸如颜色和线宽等属性,用CGPath来定义想要绘制的图 形,最后CAShapeLayer就 ...

  8. implement Google's Open Source Slam "Cartographer" demos in ROS/rviz

    Cartographer is a backpack equipped with Simultaneous Localization and Mapping (SLAM) technology. 1. ...

  9. git :设置 object-c 的忽略文件

    使用 git 命令行来进行版本控制的时候, 需要设置忽略文件. 这里能找到所有语言的忽略文件的内容:https://github.com/github/gitignore OBJECT的忽略文件内容: ...

  10. SAS Annotated Output GLM

    SAS Annotated Output GLM   在使用SAS过程中,proc glm步输出离差平方和有4种算法,分别是SS1 SS2 SS3 SS4 下面文章介绍了其中SS3的具体计算步骤和例子 ...