LeetCode数据结构—设计循环队列详解与实现

一、为什么需要循环队列

1.1 简单队列实现方法(单一头指针方法)

#include <iostream>

class MyQueue {
    private:
        // store elements
        vector<int> data;       
        // a pointer to indicate the start position
        int p_start;            
    public:
        MyQueue() {p_start = 0;}
        /** Insert an element into the queue. Return true if the operation is successful. */
        bool enQueue(int x) {
            data.push_back(x);
            return true;
        }
        /** Delete an element from the queue. Return true if the operation is successful. */
        bool deQueue() {
            if (isEmpty()) {
                return false;
            }
            p_start++;
            return true;
        };
        /** Get the front item from the queue. */
        int Front() {
            return data[p_start];
        };
        /** Checks whether the queue is empty or not. */
        bool isEmpty()  {
            return p_start >= data.size();
        }
};

int main() {
    MyQueue q;
    q.enQueue(5);
    q.enQueue(3);
    if (!q.isEmpty()) {
        cout << q.Front() << endl;
    }
    q.deQueue();
    if (!q.isEmpty()) {
        cout << q.Front() << endl;
    }
    q.deQueue();
    if (!q.isEmpty()) {
        cout << q.Front() << endl;
    }
}

1.2 缺点

上面的实现很简单,但在某些情况下效率很低。 随着起始指针的移动,浪费了越来越多的空间。 当我们有空间限制时,这将是难以接受的。一旦队列满了,我们将无法再添加更多的元素。即使我们删除了一个元素,我们也不能再次添加新的元素。只有当删除完所有元素及清空所有元素后才能重新添加元素。这样的队列效率是非常低的。即使删除了第一个元素也不能在插入多余元素! 只有在整个队列清空后才能再次使用。
在这里插入图片描述


二、循环队列

2.1 循环队列详解

  • 循环队列的head指针将永远指向队列的最前端,tail指针将永远指向队列的最尾部。初始化时,头指针和尾指针将指向同一个位置,这意味着队列为空。 (Head为头指针,Tail为尾指针)
    在这里插入图片描述

  • 当加入新数据的时候,tail指针将后移
    在这里插入图片描述

  • 循环队列中,其实数据并不一定真的被删除。当头指针加一往后移的时候,D1其实已经不是循环队列中的元素了。所以队列中的元素是Head指针和tial指针中间的数据。
    在这里插入图片描述

  • 当为指针达到最末端的时候将会重新变为0。操作实现关键取余运算!!
    在这里插入图片描述

  • 某些情况下,头指针和尾指针将会交叉。就是头指针可能会比尾指针还要大。例如下状况:当队列满了之后多次删除元素再添加元素,那么此时头指针的位置将大于尾指针。
    在这里插入图片描述


2.2 循环队列关键点

保持尾指针和头指针在我们所定义的最大队列大小当中是整个循环队列的关键点。我们可已使用取余操作保证头指针和尾指针在最大值之间循环。例:我们假设取最大值为5
head = (head+1) % maxSize
tail = (tail+1) % maxSize
在这里插入图片描述


2.3 循环队列实现中的注意事项

在实现删除元素 bool deQueue() 的操作过程中一定要对只有一个元素的状况加以考虑!!

/** Delete an element from the circular queue. Return true if the operation is successful. */
	bool deQueue() {
		if (isEmpty()) {
			cout << "Nothing to be delete! The queue is empty !" << endl;
			return false;
		}
		else {
			if (head == tail) {
				//only one element in queue,reset queue after removal
                cout << "Delete value: " << data[head] <<" one element "<< endl;
				head = -1;
				tail = -1;
				return true;
			}
			else {
				cout << "Delete value: " << data[head] << endl;
				data[head] = -1; //ressetting data that we remove to -1
				head = (head + 1) % size;
				return true;
			}

		}
	}

2.4 完整代码

class MyCircularQueue {
private:
	int head; //the beginning or front of the queue
	int tail; //the end or back of the queue
	int size; //the size of the queue
	std::vector<int> data; //the container to store the data

public:
	/** Initialize your data structure here. Set the size of the queue to be k. */
	MyCircularQueue(int k) {
		head = -1;
		tail = -1;
		size = k;
		data.resize(size);
		cout << "Circular Queue Initiated" << " " << "The size is: " << size << endl;
	}

	/** Insert an element into the circular queue. Return true if the operation is successful. */
	bool enQueue(int value) {
		if (isFull()) {
			//the queue is full
			cout << "The queue is full--enQueue" << endl;
			return false;
		}
		else {
			tail = (tail + 1) % size;
			data[tail] = value;
			cout << "enter value is: " << value << endl;
			//remember to see if the queue is empty
			if (head == -1)
				head = 0;
			return true;
		}

	}

	/** Delete an element from the circular queue. Return true if the operation is successful. */
	bool deQueue() {
		if (isEmpty()) {
			cout << "Nothing to be delete! The queue is empty !" << endl;
			return false;
		}
		else {
			if (head == tail) {
				//only one element in queue,reset queue after removal
                cout << "Delete value: " << data[head] <<" one element "<< endl;
				head = -1;
				tail = -1;
				return true;
			}
			else {
				cout << "Delete value: " << data[head] << endl;
				data[head] = -1; //ressetting data that we remove to -1
				head = (head + 1) % size;
				return true;
			}

		}
	}

	/** Get the front item from the queue. */
	int Front() {
		if (isEmpty()) {
			cout << "The queue is empty!--front" << endl;
			return -1;
		}
		else {
			cout << "The front of the queue is: " << data[head] << endl;
			return data[head];
		}

	}

	/** Get the last item from the queue. */
	int Rear() {
		if (isEmpty()) {
			cout << "Queue is empty!" << endl;
			return -1;
		}
		else {
			cout << "The rear of the queue is: " << data[tail] << endl;
			return data[tail];
		}
	}

	/** Checks whether the circular queue is empty or not. */
	bool isEmpty() {

        if (head == -1 ) {
			cout << "The queue is empty!";
			return true;
		}
		else {
			cout << "Not empty!" << endl;
			return false;
		}
	}

	/** Checks whether the circular queue is full or not. */
	bool isFull() {
		if ((head==0&&tail==size-1)||(head==tail+1)) {
			cout << "The queue is full" << endl;
			return true;
		}
		else
			return false;
	}

};


三、参考链接

https://leetcode-cn.com/explore/learn/card/queue-stack/216/queue-first-in-first-out-data-structure/863/ LeetCode题目出处

https://www.studytonight.com/data-structures/circular-queue

https://medium.com/@jhowerin/circular-queues-in-c-5dc25db1722b 特别注意,该博主的代码其实考虑并不完善,就是在删除元素的过程中漏了一个元素时的状况。 在LeetCode上是不能通过所有的测试集的!!

我在LeetCode过程中遇到不过的测试集:(只要考虑清楚一个元素的时候就可以解决)
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值