C++实现循环队列(数组模拟)【保姆级讲解】

一、循环队列的实现(数组模拟)

1、队列的特点

队列是一种先进先出的线性表

上面的队列中,1最先进入队列,7最后进入,因此1最先出队而7最后出队

2、数组模拟队列

例如:上图是一个数组,我们怎样才能让数组的行为和队列一致呢?

例如上面数组中的12,如何让他们写入呢?

直接利用数组和索引

array[0] = 1; array[1] = 2; 

这样看起来可以,但是有一个问题,我们需要时刻记得我们入队了几次,否则就无法根据索引入队了。

那么其实我们可以把这个索引用一个变量表示,每次入队只需递增它就可以了。

array[tail] = 1; ++tail;
array[tail] = 2; ++tail;

出队的话,可以利用和入队类似的办法,但数组无法删除元素,但我们可以用一个数组索引的变量表示队头的位置,每次出队只需把这个索引向递增即可。

例如让上面的12出队

++head; ++head;

解决了入队出队问题,我们就来试一下。

队空队满出队到队空

看起来还不错,但仔细观察出队到队空时,队列里面没有数了,也就是队空了,可以继续加数据,但是,表示队列头尾的变量已经到了数组的最右边的下一个索引,已经没办法再往右了,同时数组还是空的。

怎么办呢,如果队尾指针变量在到数组最后一个之后自动移动到数组第一个位置就可以解决了,如何才能做到呢?

可以利用模运算!

// 将递加操作用用模运算替代
tail = (tail+1) % 6; // 6是数组的大小
// 对于对头也是一样
head = (head+1) % 6;

tail没有到达数组末尾的时候,tail+1都小于6,因此,模6所得值还是本身,如果tail到达数组末尾,tail+1 = 6模值将会变成0,完美地将tail移动到了数组开头!

再来试一下

队空入队到队满队满

发现,当tail到数组末尾之后自动移动到开头了!

但问题就来了,要怎么判断队列满了呢?很显可以通过head = tail,可是,队空的时候它们也是相等的,这怎么办?可以改变队空或者队满的条件来解决冲突。这里可以将数组的一个格子空出来,当数组还有一个格子的时候,就当作队列已经满了。

第一种情况第二种情况

第一种情况,很明显,可以用head == tail + 1 判断队满;但第二种情况好像不行,回想之前的模运算,很快可以得到head == (tail+1) % 6,而且这个式子也适用于第一种情况!

3、编写队列结构

很明显,这个队列包含一个数组,还需要队头、队尾两个索引变量和队列大小这四个数据,同时包含入队、出队、判空、判满这四个成员函数。

// 队列结构
class Queue {
private:
    int* data;
    std::size_t head;
    std::size_t tail;
    std::size_t size;
public:
    inline Queue(std::size_t sz);
    inline ~Queue();
    void push();
    int pop();  // 为了方便测试,出队时返回出队的数据
    inline bool isEmpty();
    inline bool isFull();
}
4、入队操作

入队时,先将队尾所指位置放入需要入队的值,再将队尾后移。

代码逻辑

  • 判断是否队满
  • 没满则执行入队操作
  • 满了就输出错误信息
void Queue::push(int val) {
    if (!isFull()) {
        data[tail] = val;
        tail = (tail+1) % (size+1);
    } else {
        std::cerr << val << " push failed, Queue is full!" << std::endl;
    }
}
5、出队操作

先保存对头位置的值,再将对头指针后移,最后返回保存的值。

代码逻辑

  • 判断是否队空
  • 不空则执行出队操作
  • 空则输出错误信息
int Queue::pop() {
    if (!isEmpty()) {
        auto temp = data[head];
        head = (head+1) % (size+1);
        return temp;
    } else {
        std::cout << "Pop failed, Queue is empty!" << std::endl;
        return INT_MAX; // 用以表示队空
    }
}
6、判空和判满
inline bool Queue::isEmpty() {
    return head == tail;
}

inline bool Queue::isFull() {
    return head == (tail+1) % (size+1);
}
7、构造和析构
// 由于使用时才传入队列大小,因此需要动态数组,sz+1是为了空一格
inline Queue::Queue(std::size_t sz)
    : data(new int[sz+1]), head(0), tail(0), size(sz) { }

inline ~Queue::Queue() { delete data[]; }
8、完整代码
// Queue.h 队列类头文件

#include <cstddef>

// 队列结构
class Queue {
private:
    int* data;
    std::size_t head;
    std::size_t tail;
    std::size_t size;
public:
    inline Queue(std::size_t sz);
    inline ~Queue();
    void push(int val);
    int pop();  // 为了方便测试,出队时返回出队的数据
    inline bool isEmpty();
    inline bool isFull();
};
/*inline成员函数都定义到类的头文件中*/

// 由于使用时才传入队列大小,因此需要动态数组,sz+1是为了空一格
inline Queue::Queue(std::size_t sz)
    : data(new int[sz + 1]), head(0), tail(0), size(sz) { }

inline Queue::~Queue() { delete[] data; }


inline bool Queue::isEmpty() {
    return head == tail;
}

inline bool Queue::isFull() {
    return head == (tail + 1) % (size + 1);
}
// Queue.cpp 队列类函数的实现

#include <iostream>
#include "Queue.h"
#include <climits>

void Queue::push(int val) {
    if (!isFull()) {
        data[tail] = val;
        tail = (tail + 1) % (size + 1);
    }
    else {
        std::cerr << val << " push failed, Queue is full!" << std::endl;
    }
}

int Queue::pop() {
    if (!isEmpty()) {
        auto temp = data[head];
        head = (head + 1) % (size + 1);
        return temp;
    }
    else {
        std::cout << "Pop failed, Queue is empty!" << std::endl;
        return INT_MAX; // 用以表示队空
    }
}
// QueueTest.cpp 队列测试

#include <iostream>
#include "Queue.h"

int main(void) {
	Queue que(5);

	// 测试正常入队
	que.push(1);
	// 测试正常出队
	que.pop();
	// 一直入队,查看到数组末端会怎样
	que.push(2);
	que.push(3);
	que.push(4);
	que.push(5);
	que.push(6); 
	que.push(7);// 测试队满时入队
	// 测试出队到队空
	for (auto i = 0; i < 5; ++i)
		std::cout << que.pop() << " ";
	std::cout << std::endl;
	// 测试队空出队
	que.pop();
	/*期望输出
	7 push failed, Queue is full!
	2 3 4 5 6
	Pop failed, Queue is empty!
	*/

	return 0;
}
  • 6
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
循环队列是一种特殊的队列,它可以充分利用数组空间,实现队列的基本操作。在循环队列中,队列的头尾相连,当队列满时,可以将队列头指针指向数组的第一个位置,实现循环利用。C++实现循环队列可以使用数组和指针结构体来实现。 以下是使用数组实现循环队列C++代码: ```c++ #define MAXSIZE 10 // 定义循环队列的最大长度 typedef int ElementType; // 定义队列元素类型 class CircularQueue { private: ElementType data[MAXSIZE]; // 队列数组 int front; // 队头指针 int rear; // 队尾指针 public: CircularQueue() { // 构造函数,初始化队头和队尾指针 front = rear = 0; } bool isEmpty() { // 判断队列是否为空 return front == rear; } bool isFull() { // 判断队列是否为满 return (rear + 1) % MAXSIZE == front; } void enQueue(ElementType x) { // 入队 if (isFull()) { cout << "Queue is full!" << endl; return; } data[rear] = x; rear = (rear + 1) % MAXSIZE; } void deQueue() { // 出队 if (isEmpty()) { cout << "Queue is empty!" << endl; return; } front = (front + 1) % MAXSIZE; } void printQueue() { // 打印队列 if (isEmpty()) { cout << "Queue is empty!" << endl; return; } int i = front; while (i != rear) { cout << data[i] << " "; i = (i + 1) % MAXSIZE; } cout << endl; } }; ``` 使用指针结构体实现循环队列C++代码如下: ```c++ #define MAXSIZE 10 // 定义循环队列的最大长度 typedef int ElementType; // 定义队列元素类型 struct Queue { ElementType* data; // 队列数组 int front; // 队头指针 int rear; // 队尾指针 int size; // 队列长度 int capacity; // 队列容量 }; Queue* createQueue(int k) { // 创建空队列 Queue* q = new Queue; q->data = new ElementType[k]; q->front = q->rear = 0; q->size = 0; q->capacity = k; return q; } bool isEmpty(Queue* q) { // 判断队列是否为空 return q->size == 0; } bool isFull(Queue* q) { // 判断队列是否为满 return q->size == q->capacity; } void makeEmpty(Queue* q) { // 置空 q->front = q->rear = 0; q->size = 0; } int lengthOfQueue(Queue* q) { // 计算队列长度 return q->size; } void enQueue(Queue* q, ElementType x) { // 入队 if (isFull(q)) { cout << "Queue is full!" << endl; return; } q->data[q->rear] = x; q->rear = (q->rear + 1) % q->capacity; q->size++; } void deQueue(Queue* q) { // 出队 if (isEmpty(q)) { cout << "Queue is empty!" << endl; return; } q->front = (q->front + 1) % q->capacity; q->size--; } void printQueue(Queue* q) { // 打印队列 if (isEmpty(q)) { cout << "Queue is empty!" << endl; return; } int i = q->front; while (i != q->rear) { cout << q->data[i] << " "; i = (i + 1) % q->capacity; } cout << endl; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值