排队的时候让我们来好好理理队列的结构(内附代码实现)

队列的概念

排队是生活中非常常见的现象,比如我们排队进游乐场,排在你前面的肯定是比你早排队的人,排在你后面的肯定是比你晚排队的人,换成专业点的语言也就是FIFO(First In, First Out,先进先出) 这就是队列了。和支持入栈push()和出栈pop()类似,队列支持入队enqueue()和出队dequeue()的操作。enqueue()是从队尾塞一个元素进去,dequeue()是从队头拿一个元素出来。
在这里插入图片描述

队列的实现

基于链表实现的队列还是和栈很类似,栈是从头进从头出,队列是从尾进从头出。而基于数组实现的队列有点点复杂,我们需要两个“指针”,tail和head,因为是数组所以我们可以用下标的加减来起到指针的作用。现在最重要的问题来了,如何判断队列是否满了?经过多次画图观察,我们发现tail - head - 1 = capacity时,队列满了。 而当tail移动到最后一个位置length-1而head不在第一个位置-1时,我们可以认为这个数组内有空间,所以启动整体平移将数组内元素都往前移动一个单位,这样在tail的位置就有新的空间来塞入新元素了。整体平移要花个O(n)的时间。具体请看最后一部分的代码
在这里插入图片描述
是不是觉得上面的方法有点傻,挪head和tail的位置明显更简单嘛,所以下面就是循环链表(并没有真的把数组头尾连接,而是把数组掰弯来看),只要我们找出判断队满的条件就可以了,其实不难发现,结束条件和上面的是一样的,只不过我们要在enqueue()和front()时采取%capacity(%代表mod,%是C++求余数的符号)的方法来使得数组不会越界。具体请看最后一部分的代码
在这里插入图片描述

总结

说着容易做起来难。总结一下几个难点!

  1. 画图的时候一定要明确初始位置的head = -1,tail = 0,这个一定要在图上体现出来
  2. 写代码的时候同样要注意初始位置的head = -1,tail = 0,不然很难判断明白IsFull()的判定条件。

队列的数组版实现

main.cpp

#include <iostream>
#include "MyStack.h"
#include "MyQueue.h"
#include "CircularQueue.h"
using namespace std;

int main() {
    
    
    /********* Normal Queue ********/
    MyQueue q(5);
    cout << boolalpha << "Can we dequeue? " << q.dequeue() << endl;    // 测试空的情况下能不能dequeue
    cout << boolalpha << "Is queue empty? " << q.IsEmpty() << endl;// 测试空的情况下的返回值
    cout << q.front() << endl;    // 测试空的情况下能不能返回队头
    q.enqueue(111);             // 测试enqueue
    cout << boolalpha << "Is queue empty? " << q.IsEmpty() << endl;// 测试非空的情况下的返回值
    cout << q.front() << endl;    // 测试非空的情况下能不能返回栈顶
    cout << boolalpha << "Can we dequeue? " << q.dequeue() << endl;    // 测试非空的情况下能不能dequeue
    q.enqueue(2);
    q.enqueue(3);
    q.enqueue(4);
    q.enqueue(5);
    q.enqueue(6);
    cout << boolalpha << "Is queue full? " << q.IsFull() << endl; // 测试是否满了,满了之后会返回真
    q.showQueue();
    q.dequeue();
    cout << boolalpha << "Is queue full? " << q.IsFull() << endl; // 测试是否整体平移
    cout << boolalpha << "Can we enqueue? " << q.enqueue(7)  << endl; //测试整体平移后还能不能enqueue
    q.showQueue();

    cout << endl;

    /********* Circular Queue ********/
    CircularQueue cq(5);
    cout << boolalpha << "Can we dequeue? " << cq.dequeue() << endl;    // 测试空的情况下能不能dequeue
    cout << boolalpha << "Is queue empty? " << cq.IsEmpty() << endl;// 测试空的情况下的返回值
    cout << cq.front() << endl;    // 测试空的情况下能不能返回队头
    cq.enqueue(111);             // 测试enqueue
    cout << boolalpha << "Is queue empty? " << cq.IsEmpty() << endl;// 测试非空的情况下的返回值
    cout << cq.front() << endl;    // 测试非空的情况下能不能返回栈顶
    cout << boolalpha << "Can we dequeue? " << cq.dequeue() << endl;    // 测试非空的情况下能不能dequeue
    cq.enqueue(2);
    cq.enqueue(3);
    cq.enqueue(4);
    cq.enqueue(5);
    cq.enqueue(6);
    cout << boolalpha << "Is queue full? " << cq.IsFull() << endl; // 测试是否满了,满了之后会返回真
    cq.showQueue();
    cq.dequeue();
    cout << boolalpha << "Is queue full? " << cq.IsFull() << endl; // 测试是否整体平移
    cout << boolalpha << "Can we enqueue? " << cq.enqueue(7)  << endl; //测试整体平移后还能不能enqueue
    cq.showQueue();

    return 0;
}

普通队列

MyQueue.h

//
// Created by Sky on 2021/3/14.
//

#ifndef DATA_STRUCTURE_PRACTICES_MYSTACK_H
#define DATA_STRUCTURE_PRACTICES_MYSTACK_H
#include <iostream>
using namespace std;

class MyStack{
    
    
public:
    MyStack(int n);
    bool isEmpty();
    bool isFull();
    bool push(int num);
    bool pop();
    int top();
    ~MyStack();

private:
    void expand();
    int* data;
    int capacity;
    int size;
};


#endif //DATA_STRUCTURE_PRACTICES_MYSTACK_H

MyQueue.cpp

//
// Created by Sky on 2021/3/14.
//

#include "MyStack.h"
MyStack::MyStack(int n) {
    
    
    int* temp = new int[n];
    data = temp;
    capacity = n;
    size = 0;
    cout << "Stack has been created" << endl;
}
MyStack::~MyStack() {
    
    
    delete data;
    cout << "Stack has been deleted" << endl;
}

bool MyStack::isFull() {
    
    
    if(capacity == size){
    
    
        expand();
        return true;
    }
    return false;
}

bool MyStack::isEmpty() {
    
    
    if(size == 0)
        return true;
    return false;
}

bool MyStack::push(int num) {
    
    
    if (isFull())
        return false;
    data[size++] = num;
    return true;
}

bool MyStack::pop() {
    
    
    if(isEmpty())
        return false;
    --size;
    return true;
}

int MyStack::top() {
    
    
    if (isEmpty())
        return -1;
//    cout << data[size] << endl;
    return data[size-1];
}

void MyStack::expand() {
    
    
    int* temp = new int [2*capacity];
    for (int i = 0; i < capacity; i++){
    
    
        temp[i] = data[i];
    }
    delete data;
    data = temp;
    capacity *= 2;
}

循环队列

CircularQueue.h

//
// Created by Sky on 2021/3/15.
//

#ifndef DATA_STRUCTURE_PRACTICES_CIRCULARQUEUE_H
#define DATA_STRUCTURE_PRACTICES_CIRCULARQUEUE_H
# include <iostream>
using namespace std;

class CircularQueue {
    
    
public:
    CircularQueue(int n);
    ~CircularQueue();
    bool IsEmpty();
    bool IsFull();
    bool enqueue(int n);
    bool dequeue();
    int front();
    void showQueue();

private:
    int* data;
    int capacity;
    int head;
    int tail;
};


#endif //DATA_STRUCTURE_PRACTICES_CIRCULARQUEUE_H

CircularQueue.cpp

//
// Created by Sky on 2021/3/15.
//

#include "CircularQueue.h"

CircularQueue::CircularQueue(int n) {
    
    
    int* temp = new int [n];
    data = temp;
    capacity = n;
    head = -1;
    tail = 0;
    cout << "Queue has been created" << endl;
}

CircularQueue::~CircularQueue() {
    
    
    delete data;
    cout << "Queue has been deleted" << endl;
}

bool CircularQueue::IsEmpty() {
    
    
    if (tail - head == 1)
        return true;
    return false;
}

bool CircularQueue::IsFull() {
    
    
    if(tail - head - 1 == capacity)
        return true;
    return false;
}

bool CircularQueue::enqueue(int n) {
    
    
    if(IsFull())
        return false;
    data[tail%capacity] = n;
    tail++;
    return true;
}

bool CircularQueue::dequeue() {
    
    
    if(IsEmpty())
        return false;
    head++;
    return true;
}

int CircularQueue::front() {
    
    
    if(IsEmpty())
        return -1;
    return data[head%capacity+1];
}

void CircularQueue::showQueue() {
    
    
    cout << "head = " << head << ", tail = " << tail << endl;
    int count = 1;
    for(int i = head+1; i%capacity < tail-head-1; i++){
    
    
        cout << data[i%capacity] << ' ';
        if (count >= tail-head-1)
            break;
        count++;
    }
    cout << endl;
}


猜你喜欢

转载自blog.csdn.net/skywuuu/article/details/114819254