C++循环队列实现模型

本文实例讲述了C++循环队列实现模型。分享给大家供大家参考。具体分析如下:

前段时间在知乎上看到这样一个小题目:

用基本类型实现一队列,队列要求size是预先定义好的的。而且要求不可以使用语言自带的api,如C++的STL。普通的实现很简单,但是现在要求要尽可能的时间和空间复杂度的优化,要和语言自带的api比较时间和空间。这个队列还要支持如下的操作:

constructor: 初始化队列

enqueue:入队

dequeue:出队

队列是一种基本的数据结构,在平常的应用中十分广泛,多数情况队列都是用链表实现的。但是对于本题而言,用链表实现就有这样一个问题:由于每个结点都存在至少一个指向前一个结点或后一个结点的指针,这就带来了空间复杂度的加大,所以并不太适合要求。

这个时候我想到了boost中的boost::circular_buffer,它是通过类似于数组的底层结构实现的一个循环buffer。而数组的优点是空间复杂度够小(除去维持数据结构的索引项,空间复杂度为线性),再实现成循环结构可以最大化的利用空间。而且在队列这样一种只在前后端插入删除的情况下,其push和pop的时间复杂度也只有O(1)。

基本实现如下:

代码如下:

#ifndef __CIRCULAR_QUEUE_H__
#define __CIRCULAR_QUEUE_H__

#include <stddef.h>

template<typename T>
class circular_queue
{
public:
    explicit circular_queue(size_t maxsize)
        : maxsize_(maxsize + 1), head_(0), rear_(0)
    {
        array_ = new T[maxsize_];
    }

circular_queue(size_t maxsize, const T& val)
        : maxsize_(maxsize + 1), head_(0), rear_(0)
    {
        array_ = new T[maxsize_];
        for (size_t i = 0; i != maxsize; ++i)
        {
            array_[i] = val;
        }
        rear_ = maxsize;
    }

circular_queue(const circular_queue& rhs)
        : maxsize_(rhs.maxsize_), head_(rhs.head_), rear_(rhs.rear_)
    {
        array_ = new T[maxsize_];
        for (int i = 0; i != maxsize_; ++i)
        {
            array_[i] = rhs.array_[i];
        }
    }

~circular_queue()
    {
        delete [] array_;
    }

circular_queue& operator=(const circular_queue& rhs)
    {
        if (this == &rhs)
        {
            return *this;
        }
        delete [] array_;
        maxsize_ = rhs.maxsize_;
        head_ = rhs.head_;
        rear_ = rhs.rear_;
        array_ = new T[maxsize_];
        for (int i = 0; i != maxsize_; ++i)
        {
            array_[i] = rhs.array_[i];
        }
        return *this;
    }

bool empty() const
    {
        return head_ == rear_;
    }

size_t size() const
    {
        return (rear_ - head_ + maxsize_) % maxsize_;
    }

T& front()
    {
        return array_[head_];
    }

const T& front() const
    {
        return array_[head_];
    }

void push(const T& val)
    {
        if ((rear_ + 1) % maxsize_ != head_)
        {
            array_[rear_] = val;
            rear_ = (rear_ + 1) % maxsize_;
        }
    }

void pop()
    {
        if (head_ != rear_)
        {
            head_ = (head_ + 1) % maxsize_;
        }
    }

private:
    size_t  maxsize_;
    int     head_;
    int     rear_;
    T*      array_;
};

#endif

队列长度 = 数组长度 - 1

预留了一个单位的数组元素空间作为队尾标记。

这个只是简陋的实现,没有考虑到一些情况,比如线程安全、STL算法,函数对象的兼容等。代码只是简单的测试了一下,如有错误欢迎指正:)

总的来说,这种思路的循环队列有以下优点:

1、使用固定的内存,不需要隐式或意外的内存分配。

2、从前端或后端进行快速的常量时间的插入和删除元素。

3、快速的常量时间的对元素进行随机访问。(如果需要的话可以定义operator[])

4、适用于实时和对性能有严格要求的应用程序。

还可以进一步扩展,当队列满的时候,从一端插入则覆盖冲洗掉另一端的数据,这样的一个模型可以应用于这些场合:

保存最近接收到的取样数据,在新的取样数据到达时覆盖最旧的数据。
一种用于保存特定数量的最后插入元素的快速缓冲。
高效的固定容量FIFO(先进先出)或LIFO(后进先出)队列,当队列满时删除最旧的(即最早插入的)元素。

希望本文所述对大家的C++程序算法设计有所帮助。

(0)

相关推荐

  • C++ 数据结构之kmp算法中的求Next()函数的算法

    C++ 数据结构之kmp算法中的求Next()函数的算法 实例代码: #include <iostream> using namespace std; void preKmp(char *c, int m, int Next[]) { int i=1,j=-1; Next[0]=-2; while(i<m) { if(j==-2) { Next[i]=-1; i++; j=-1; } ++j; if(i==m) return; if(c[i]==c[j]) { Next[i]=j; ++

  • C++数据结构与算法之判断一个链表是否为回文结构的方法

    本文实例讲述了C++判断一个链表是否为回文结构的方法.分享给大家供大家参考,具体如下: 题目: 给定一个链表头节点head,请判断是否为回文结构 例如: 1->2->1 true 1->2->2->1 true 1->2->3->4->2->1 false 解题思路及代码 1.找到链表中间节点,然后将链表中间节点的右边所有节点放入一个栈中. 2.然后从链表首节点和栈顶元素一一对比,不相等则return false. 算法C++代码: 链表节点结构

  • C++中用两个标准容器stack,实现一个队列的方法详解

    代码如下所示: 复制代码 代码如下: // StackToQueue.cpp : 定义控制台应用程序的入口点.//用两个标准容器stack,实现一个队列#include "stdafx.h"#include <iostream>#include <stack>using namespace std;template <class T>class StackToQueue{public: StackToQueue() {  stack1;  stack

  • 解析C++无锁队列的实现代码

    本文给出一种C++无锁队列的实现代码,主要用于一个线程读取数据另外一个线程写数据 复制代码 代码如下: #ifndef LOCK_FREE_QUEUE_H_#define LOCK_FREE_QUEUE_H_ //不加锁队列,适合一个线程读取,一个线程写#include <list>template <typename T>class LockFreeQueue{    public:        LockFreeQueue()        {             list

  • C++ 数据结构实现两个栈实现一个队列

    C++ 数据结构实现两个栈实现一个队列 栈为后进先出,队列为先进先出 用两个栈实现一个队列.是一个比较经典的问题. 看到这个问题,我的第一个解题思路为: 定义两个栈,s1,s2.s1作为入队列栈,s2作为出队列栈: 入队列:每次入队列的时候,将数值压入s1栈中: 出队列:出队列时,将s1中的所有数据,压进s2栈中,然后删除s2的栈顶数据,然后再将s2中的剩余数据压入s1中. 在这其中s1是一个存储空间,s2是一个辅助空间. 进一步想一下上述办法,在出队列时,每一次都要将s1倒进s2,然后删除s2

  • C++数据结构之实现循环顺序队列

    数据结构–用C++实现循环顺序队列 队列的操作特性:先进先出 队列中元素具有相同类型 相邻元素具有前驱和后继关系 设置队头.队尾两个指针,以改进出队的时间性能 约定:队头指针front指向队头元素的前一个位置,队尾指针rear指向队尾元素 为了解决假溢出,我们将存储队列的数组头尾相接,从而产生了循环队列. 如何判断循环队列队空? 队空:front=rear 如何盘对循环队列堆满? 队满:front=rear 那么问题就来了,队空和队满的判断条件相同,为了避免队满时产生队空的判断或者相反,我们需要

  • C++中实现队列类链式存储与栈类链式存储的代码示例

    队列类链式存储 代码: linkqueue.hpp // 队列类 #pragma once #include "linklist.hpp" template <typename T> class LinkQueue { public: LinkQueue(); ~LinkQueue(); public: int clear(); int append(T &t); int retieve(T &t); int header(T &t); int le

  • C++ STL入门教程(3) deque双向队列使用方法

    一.简介 deque(Double Ended Queues,双向队列)和向量很相似,但是它允许在容器头部快速插入和删除(就像在尾部一样). 二.完整程序代码 /*请务必运行以下程序后对照阅读*/ #include <deque> #include <iostream> #include <algorithm> #include <stdexcept> using namespace std; void print(int num) { cout <&

  • C++中队列的建立与操作详细解析

    什么是队列结构 队列结构是从数据运算来分类的,也就是说队列结构具有特殊的运算规则.而从数据的逻辑结构来看,队列结构其实就是一种线性结构.如果从数据的存储结构来进一步划分,队列结构可以分成两类. 顺序队列结构:即使用一组地址连续的内存单元依次保存队列中的数据.在程序中,可以定义一个指定大小的结构数组来作为队列. 链式队列结构:即使用链表形式保存队列中各元素的值. 在队列结构中允许对两端进行操作,但是两端的操作不同.在表的一端只能进行删除操作,称为队头:在表的另一端只能进行插入操作,称为队尾.如果队

  • C++非递归队列实现二叉树的广度优先遍历

    本文实例讲述了C++非递归队列实现二叉树的广度优先遍历.分享给大家供大家参考.具体如下: 广度优先非递归二叉树遍历(或者说层次遍历): void widthFirstTraverse(TNode* root) { queue<TNode*> q; // 队列 q.enqueue(root); TNode* p; while(q.hasElement()) { p = q.dequeue(); // 队首元素出队列 visit(p); // 访问p结点 if(p->left) q.enqu

  • C++数据结构与算法之双缓存队列实现方法详解

    本文实例讲述了C++数据结构与算法之双缓存队列实现方法.分享给大家供大家参考,具体如下: "双缓存队列"是我在一次开发任务中针对特殊场景设计出来的结构.使用场景为:发送端持续向接收端发送数据包--并且不理会接收端是否完成业务逻辑.由于接收端在任何情况下停止响应即可能产生数据丢失,因此无法简单的设计一条线程安全队列来对数据写入或读取(读取数据时将队列上锁视为对写入的停止响应). 鉴于此,我的设计思路如下: 接收端首先向A队列中写入数据,然后当数据处理请求到来的时候切换到B队列继续写入,之

  • C++ 中消息队列函数实例详解

    C++ 中消息队列函数实例详解 1.消息队列结构体的定义 typedef struct{ uid_t uid; /* owner`s user id */ gid_t gid; /* owner`s group id */ udi_t cuid; /* creator`s user id */ gid_t cgid; /* creator`s group id */ mode_t mode; /* read-write permissions 0400 MSG_R 0200 MSG_W*/ ul

随机推荐