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

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

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

队列


队列的模型

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

队列的编程实现方式

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

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

队列的基本元素

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

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

队列的基本操作

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

基本操作的实现

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

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

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

队列判空:通过长度判断

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

队列长度:直接返回

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

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

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

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

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

C++实现步骤

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

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

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

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

课程笔记

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

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

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

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

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

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

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

标准C++代码

  1. #pragma once
  2. //MyQueue.h
  3. //环形队列C++实现
  4. class MyQueue
  5. {
  6. public:
  7. MyQueue(int queueCapacity); //InitQueue(&Q)创建队列
  8. virtual ~MyQueue(); //DestroyQueue(&Q)销毁队列
  9. void ClearQueue(); //ClearQueue(&Q)清空队列
  10. bool QueueEmpty() const; //QueueEmpty(&Q)判空队列
  11. int QueueLength() const; //QueueLength(Q)队列长度
  12. bool QueueFull() const;
  13.  
  14. bool EnQueue(int element); //EnQueue(&Q, element)新元素入队
  15. bool DeQueue(int &element); //DeQueue(&Q, &element)首元素出队
  16. void QueueTraverse(); //QueueTraverse(Q, visit())遍历队列
  17. private:
  18. int *m_pQueue; //队列数组数组
  19. int m_iQueueLen; //队列元素个数
  20. int m_iQueueCapacity; //队列数组容量
  21.  
  22. int m_iHead;
  23. int m_iTail;
  24. };
  1. //MyQueue.cpp
  2. #include"MyQueue.h"
  3. #include<iostream>
  4. using namespace std;
  5.  
  6. MyQueue::MyQueue(int queueCapacity)
  7. {
  8. m_iQueueCapacity = queueCapacity;
  9. m_iHead = 0;
  10. m_iTail = 0;
  11. m_iQueueLen = 0;
  12. m_pQueue = new int[m_iQueueCapacity];
  13. }
  14.  
  15. MyQueue::~MyQueue()
  16. {
  17. delete[]m_pQueue;
  18. m_pQueue = nullptr;
  19. }
  20.  
  21. void MyQueue::ClearQueue()
  22. {
  23. m_iHead = 0;
  24. m_iTail = 0;
  25. m_iQueueLen = 0;
  26. }
  27.  
  28. bool MyQueue::QueueEmpty() const
  29. {
  30. if (m_iQueueLen == 0)
  31. return true;
  32. else
  33. return false;
  34. }
  35.  
  36. bool MyQueue::QueueFull() const
  37. {
  38. if (m_iQueueLen == m_iQueueCapacity)
  39. return true;
  40. else
  41. return false;
  42. }
  43.  
  44. int MyQueue::QueueLength() const
  45. {
  46. return m_iQueueLen;
  47. }
  48.  
  49. bool MyQueue::EnQueue(int element)
  50. {
  51. if (QueueFull())
  52. return false;
  53. else
  54. {
  55. m_pQueue[m_iTail] = element;
  56. m_iTail++;
  57. m_iTail = m_iTail % m_iQueueCapacity;
  58. m_iQueueLen++;
  59. return true;
  60. }
  61. }
  62.  
  63. bool MyQueue::DeQueue(int &element)
  64. {
  65. if (QueueEmpty())
  66. return false;
  67. else
  68. {
  69. element = m_pQueue[m_iHead];
  70. m_iHead++;
  71. m_iHead = m_iHead % m_iQueueCapacity;
  72. m_iQueueLen--;
  73. return true;
  74. }
  75. }
  76.  
  77. void MyQueue::QueueTraverse()
  78. {
  79. for (int i = m_iHead; i < m_iQueueLen + m_iHead; i++)
  80. {
  81. cout << m_pQueue[i%m_iQueueCapacity] << endl;
  82. }
  83. }
  1. //demo.cpp
  2. #include<iostream>
  3. #include"MyQueue.h"
  4. using namespace std;
  5.  
  6. int main()
  7. {
  8. MyQueue *p = new MyQueue(4);
  9. p->EnQueue(1);
  10. p->EnQueue(0);
  11. p->EnQueue(11);
  12. p->QueueTraverse();
  13. p->ClearQueue();
  14. cout << "after clear: " << endl;
  15. p->QueueTraverse();
  16. if (p->QueueEmpty())
  17. cout << "Empty queue" << endl;
  18. else
  19. cout << "Not Empty" << endl;
  20. p->EnQueue(5);
  21. p->EnQueue(15);
  22. p->EnQueue(25);
  23. cout << p->QueueLength() << endl;
  24. int tmp;
  25. p->DeQueue(tmp);
  26. cout << "tmp is " << tmp << endl;
  27. cout << p->QueueLength() << endl;
  28. return 0;
  29. }

 

实际应用

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

  1. //Customer.h
  2. #pragma once
  3. #include <string>
  4. using namespace std;
  5.  
  6. class Customer
  7. {
  8. public:
  9. Customer(string name = "", int age = 0);
  10. void printInfo() const;
  11. private:
  12. string m_strName;
  13. int m_iAge;
  14. };
  1. //Customer.cpp
  2. #include<iostream>
  3. #include"Customer.h"
  4. using namespace std;
  5.  
  6. Customer::Customer(string name, int age)
  7. {
  8. m_strName = name;
  9. m_iAge = age;
  10. }
  11.  
  12. void Customer::printInfo() const
  13. {
  14. cout << "Name: " << m_strName << endl;
  15. cout << "Age: " << m_iAge << endl;
  16. cout << "=================" << endl;
  17. }
  1. //demo.cpp
  2. #include<iostream>
  3. #include"MyQueue.h"
  4. using namespace std;
  5.  
  6. int main()
  7. {
  8. MyQueue *p = new MyQueue(4);
  9. Customer c1("zhangsan", 20);
  10. Customer c2("lisi", 30);
  11. Customer c3("wangwu", 24);
  12.  
  13. p->EnQueue(c1);
  14. p->EnQueue(c2);
  15. p->EnQueue(c3);
  16.  
  17. p->QueueTraverse();
  18.  
  19. cout << endl;
  20. Customer c4;
  21. p->DeQueue(c4);
  22. cout << "this is c4: " << endl;
  23. c4.printInfo();
  24.  
  25. cout << "this is QueueTraverse: " << endl;
  26. p->QueueTraverse();
  27. return 0;
  28. }

 

使用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. LYK 快跑!(run)

    LYK 快跑!(run)Time Limit:5000ms Memory Limit:64MB[题目描述] LYK 陷进了一个迷宫! 这个迷宫是网格图形状的. LYK 一开始在(1,1)位置, 出口在 ...

  2. (转)Linux下安装rar fou linux

    在Linux下安装rar fou linux rar for linux 软件下载地址:http://www.rarsoft.com/download.htm 到目前为止最新的版本为4.10 beta ...

  3. 插入排序和一点小感悟(c++版)

    很早之前,为了应付数据结构考试.花了一星期多看了数据结构,当时觉得也没什么难的. 过了老久,总算是招报应了,做笔试题发现其实所有理解只是在表面,实际上我并不会实现,确实是这样,学术这东西真没捷径,还是 ...

  4. JAVA常用数据结构及原理分析

    JAVA常用数据结构及原理分析 http://www.2cto.com/kf/201506/412305.html 前不久面试官让我说一下怎么理解java数据结构框架,之前也看过部分源码,balaba ...

  5. Web文件的ContentType类型收集

    ".*"="application/octet-stream"".001"="application/x-001"&qu ...

  6. SqlSever基础 Upper函数 返回字符串的大写形式

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

  7. #查找列表中元素,移除每个元素的空格,并查找以 a或A开头 并且以 c 结尾的所有元素

    #!/usr/bin/env python #查找列表中元素,移除每个元素的空格,并查找以 a或A开头 并且以 c 结尾的所有元素. #    li = ["alec", &quo ...

  8. C#开发COM组件

    1.每个COM组件所有对外公布的方法都必须通过接口形式实现: 2.由于.Net下编译的COM组件并等同于C编译的COM组件,所以存在必须在运行目标机器注册的情况,对此.Net下编译的COM组件必须为程 ...

  9. (1)定义一个接口Compute含有一个方法int computer(int n,int m); (2)设计四个类分别实现此接口,完成+-*/运算 (3)设计一个类UseCompute,含有方法: public void useCom(Compute com, int one, int two) (4)设计一个测试类

    package b; public interface Computer { int computer(int n,int m); } package b; public class Jia impl ...

  10. BZOJ 2584: [Wc2012]memory(扫描线+线段树)

    题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2584 题意:给出平面n个线段,任意两个线段严格不相交,且每个线段不平行于坐标轴.移 ...