C++ 循环队列

文章目录

总结归纳

  1. 队列实际上就是现实生活中的排队,队头的人先走,新来的人排到队尾。先进先出,后进后出。
  2. 队列的实现,需要一个队头指针,一个队尾指针,用于入队和出队。对于循环队列,初始化时需将 Q.front = Q.rear = 0,Q.front 指向队头,Q.rear 指向新元素入队的位置。
  3. 循环队列,物理上仍然是申请一片连续的内存空间,但通过 (Q.rear + 1) % MaxSize == Q.front 的判断条件从逻辑上模拟环状空间,从而实现循环队列。
  4. 代码中值得一提的是 GetLength(SqQuene &Q, ElemType &len) 函数(获取队列长度),当有元素出队时,实际上只是将 Q.front 前移,从逻辑上出队,原先的队头仍然存在,当下次有新元素入队时直接进行覆盖,所以长度的遍历应从 Q.front 开始;而在队列的初始化中,我们设置的是 Q.front = Q.rear = 0 ,例如:当队列中有一个元素时,Q.front = 0,而 length = 1,所以我们需要将这个 1 补回来,才是真正的队列长度。
  5. 以往的 GetLength 代码,总是通过指针来进行遍历,而循环队列能不能用指针获取长度,我的看法是不可以(如果可以麻烦告诉我)。之前的数据结构能用指针遍历,是因为 struct 结构体中就定义了指针,所以可以申请一个结构体指针指向该结构体,通过 p = p->next 来进行遍历;而循环队列的实质仍然是一片连续的内存空间,诚然你可以申请一个数组指针 int *p = Q.data,但又回到了刚才的问题:在已有元素出队的情况下,Q.data 的第一个元素就不是队头,这会影响到队列长度的判断。而对于链式数据结构,删了就是删了,直接 delete / free ,就没有这个问题。
// 获取队列长度
bool GetLength(SqQuene &Q, ElemType &len) {
    if (Q.front == Q.rear) {
        len = 0;
    } else {
        len = Q.front; // 指向队头
        while ((len + 1) % MaxSize != Q.rear) {
            len++;
        }
        len = len - Q.front + 1; // 如果有元素出队,会导致Q.front不为0,影响长度的判断,且初始化队列时,Q.front置为0,同样影响长度
    }
    return true;
}

代码实现

/*
循环队列
*/

#include <iostream>

#define MaxSize 10 // 队列中元素的最大个数

using namespace std;

typedef int ElemType;

struct SqQuene {
    ElemType data[MaxSize]; // 队列中元素的最多个数
    int front, rear;        // 队头指针,队尾指针
};

// 初始化队列
void InitQuene(SqQuene &Q) { Q.front = Q.rear = 0; }

// 队列判空
bool QueneEmpty(SqQuene &Q) {
    if (Q.front == Q.rear) {
        return true;
    } else {
        return false;
    }
}

// 入队
bool EnQuene(SqQuene &Q, ElemType x) {
    if ((Q.rear + 1) % MaxSize == Q.front) { // 队满
        return false;
    } else {
        Q.data[Q.rear] = x; // 赋值给下一队尾
        Q.rear = (Q.rear + 1) %
                 MaxSize; // 在逻辑上将存储空间变为“环状”,物理上仍然是静态数组
        return true;
    }
}

// 出队
bool DeQuene(SqQuene &Q, ElemType &x) {
    if (Q.rear == Q.front) { // 队空
        return false;
    } else {
        x = Q.data[Q.front];
        Q.front = (Q.front + 1) % MaxSize; // 队头指针后移
        return true;
    }
}

// 获取队头元素
bool GetHead(SqQuene &Q, ElemType &x) {
    if (Q.rear == Q.front) { // 队空
        return false;
    } else {
        x = Q.data[Q.front];
        return true;
    }
}

// 获取队列长度
bool GetLength(SqQuene &Q, ElemType &len) {
    if (Q.front == Q.rear) {
        len = 0;
    } else {
        len = Q.front; // 指向队头
        while ((len + 1) % MaxSize != Q.rear) {
            len++;
        }
        len = len - Q.front + 1; // 如果有元素出队,会导致Q.front不为0,影响长度的判断,且初始化队列时,Q.front置为0,同样影响长度
    }
    return true;
}

int main() {
    SqQuene Q;
    InitQuene(Q);

    ElemType head, pop, length;

    for (int i = 1; i < 6; i++) {
        EnQuene(Q, i);
    }

    GetHead(Q, head);
    cout << "队头元素:" << head << endl;

    GetLength(Q, length);
    cout << "队列长度:" << length << endl;

    DeQuene(Q, pop);
    cout << "出队元素:" << pop << endl;

    GetHead(Q, head);
    cout << "队头元素:" << head << endl;

    GetLength(Q, length);
    cout << "队列长度:" << length << endl;
}
上一篇:队列及其操作


下一篇:容器:deque用法及示例