C++实现双端队列(数组模拟)【每一步详细深入讲解,代码清晰、简单、易懂】

一、数组实现双端队列

0、一些共识
1)左右指针的位置

例如上图这样一个双端队列,刚开始队列为空的时候,左右指针指向同一个位置;

这时候,如果从左边入队1,右边入队2

初始将左指针所指位置填充1,再左移左指针将右指针所指位置填充2,再右移右指针

发现,左边入队是正常,但,右边入队时入队的值覆盖了之前的值!那该怎么改?

解决思路

发现,左右入队是都是填充值,后移动指针,而开始的时候左右指针指向同一处,写值会覆盖。

因此,有如下两种解决方法:

1、改进入队方法:左边依旧先写值,后移动,右边则先移动,后写值,结果如下

初始将左指针所指位置填充1,再左移左指针先右移右指针,后填充2

但是,这样怎么看怎么别扭,左边和右边都执行了入队,但左指针位置无元素,右指针位置却有,而且左右入队操作不同,不太符合通用原则。

2、改进指针位置:既然上述问题是由于左右指针指向同一个位置造成的,那么就可以让指针错位,初始时右指针在左指针右边一格

初始将左指针所指位置填充1,再左移左指针将右指针所指位置填充2,再右移右指针
2)队空,队满的条件

经过上述讨论,可以看出,left + 1 == right时,队列是空的,那么,这是不是就是判断队列为空的条件呢?

在此之前,我们先来看看左指针和右指针在队列未满但到达边界时如何处理

问题和期望的结果:如左图,左指针已经到了左边界,但队列还没满按理说应该可以左入队,再次入队之后左指针应该到达最右边,这样才能实现继续入队,现在只要实现左指针到达左边界时再入队,指针移动到最右边的操作。

**数学依据:**模运算!!!经过思考,发现一个小于B的数A模B依然等于A,而如果A等于B,那A模B就等于0,-1+B模B等于B-1,而A加上任意个B 再模B依然等于A

**结论:**利用这个性质,左指针的移动可以改成(left - 1 + size) % size,当左指针没有达到左边界时,该操作只是向左移动一格,而到达左边界时就移动到最右边!

这时,右指针达到右边界依然可以利用模运算,公式为(right + 1) % size
出队时左右指针的逻辑正好和入队相反

队空的条件:

队空有如下两种情况:

left + 1 == right(left + 1) % size == right

经过上面讨论,我们可以轻松得出这两种情况的表达式,而第一种情况也可以用第二个表达式表示,因此我们得到了队空的通用表示(left + 1) % size == right

队满的条件:

假设从右边一直入队直到队满

如果数组中填满元素,那么,右指针正好在左指针右边,这和队空的条件一样,会产生冲突!
解决方法很简单,只要空出一个格子,让队满的条件改为左右指针相等left == right

1、双端队列的定义

双端队列需要一个数组以及表示两端的指针,还有表示队列大小的变量;
需要左右入队、左右出队操作,而入队出队又需要判断队空和队满;
同时,构造和析构也不能少

class Deque {
private:
    int* deq;  // 数组
    std::size_t left;  // 左指针
    std::size_t right; // 右指针
    std::size_t size;
private:
    inline bool empty();
    inline bool full();
public:
    void lpush(int);
    void rpush(int);
    int lpop();
    int rpop();
    Deque(std::size_t);
    ~Deque();
};
2、入队操作
  • 判断队满与否
    • 满则输出错误信息
    • 未满则入队
// 左入队
void Deque::lpush(int val) {
	if (full()) {
		std::cerr << "Deque is full, lpush failed!" << std::endl;
	} else {
		deq[left] = val;
		left = (left - 1 + size) % size;
	}
}

// 右入队
void Deque::rpush(int val) {
	if (full()) {
		std::cerr << "Deque is full, rpush failed!" << std::endl;
	} else {
		deq[right] = val;
		right = (right + 1) % size;
	}
}
3、出队操作
  • 判断队空与否
    • 空则输出错误信息
    • 不空则出队
// 左出队
int Deque::lpop() {
	if (empty()) {
		std::cerr << "Deque is empty, lpop failed!" << " ";
		return INT_MAX;
	} else {
		left = (left + 1) % size; // 只需移动指针,不需要改动值
		return deq[left];
	}
}

// 右出队
int Deque::rpop() {
	if (empty()) {
		std::cerr << "Deque is empty, rpop failed!" << " ";
		return INT_MAX;
	} else {
		right = (right - 1 + size) % size; // 只需移动指针,不需要改动值
		return deq[right];
	}
}
4、队空、队满操作
// 因为队空队满操作十分简单,因此,我让他们内联
// 队空
inline bool Deque::empty() {
    return (left + 1) % size == right;
}

// 队满
inline bool Deque::full() {
    return left == right;
}
5、完整代码
// Deque.h双端队列定义
#include <cstddef>

class Deque {
private:
	int* deq;  // 数组
	std::size_t left;  // 左指针
	std::size_t right; // 右指针
	std::size_t size;
private:
	inline bool empty();
	inline bool full();
public:
	void lpush(int);
	void rpush(int);
	int lpop();
	int rpop();
	inline Deque(std::size_t);
	inline ~Deque();
};

// 给数组开辟sz+1是为了给判断队满空出一格
Deque::Deque(std::size_t sz) 
	: deq(new int[sz + 1]()), left(0), right(1), size(sz+1) { }

Deque::~Deque() {
	delete[] deq;
}

// 因为队空队满操作十分简单,因此,我让他们内联
// 队空
inline bool Deque::empty() {
	return ((left + 1) % size == right);
}

// 队满
inline bool Deque::full() {
	return left == right;
}
// Deque.cpp双端队列函数实现
#include <iostream>
#include <cstddef>

#include "Deque.h"

// 左入队
void Deque::lpush(int val) {
	if (full()) {
		std::cerr << "Deque is full, lpush failed!" << std::endl;
	} else {
		deq[left] = val;
		left = (left - 1 + size) % size;
	}
}

// 右入队
void Deque::rpush(int val) {
	if (full()) {
		std::cerr << "Deque is full, rpush failed!" << std::endl;
	} else {
		deq[right] = val;
		right = (right + 1) % size;
	}
}

// 左出队
int Deque::lpop() {
	if (empty()) {
		std::cerr << "Deque is empty, lpop failed!" << " ";
		return INT_MAX;
	} else {
		left = (left + 1) % size; // 只需移动指针,不需要改动值
		return deq[left];
	}
}

// 右出队
int Deque::rpop() {
	if (empty()) {
		std::cerr << "Deque is empty, rpop failed!" << " ";
		return INT_MAX;
	} else {
		right = (right - 1 + size) % size; // 只需移动指针,不需要改动值
		return deq[right];
	}
}
// Deque_test.cpp双端队列测试文件
#include <iostream>

#include "Deque.h"

int main(int) {
	Deque que(5); // 定义大小为5的双端队列
	
	// 模拟栈的先入后出
	for (auto i = 0; i < 5; ++i)
		que.rpush(i);
	//测试队满入队
	que.lpush(0);
	for (auto i = 0; i < 5; ++i)
		std::cout << que.rpop() << " ";
	std::cout << std::endl;
	
	// 模拟队列的先入先出
	for (auto i = 0; i < 5; ++i)
		que.rpush(i);
	for (auto i = 0; i < 5; ++i)
		std::cout << que.lpop() << " ";
	std::cout << std::endl;
	
	/*
	* 期望输出:
	* Deque is full, lpush failed!
	* 4 3 2 1 0
	* 0 1 2 3 4
	*/

	return 0;
}
  • 15
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是用C++实现双端队列代码详细步骤: ```cpp #include <iostream> using namespace std; #define MAXSIZE 100 // 定义双端队列的最大长度 class Deque { private: int data[MAXSIZE]; // 双端队列的数据存储数组 int left; // 左指针 int right; // 右指针 public: Deque() { // 构造函数,初始化左右指针 left = 0; right = 0; } bool isEmpty() { // 判断队列是否为空 return left == right; } bool isFull() { // 判断队列是否已满 return (right + 1) % MAXSIZE == left; } void push_front(int x) { // 在队头插入元素 if (isFull()) { cout << "Deque is full!" << endl; return; } left = (left - 1 + MAXSIZE) % MAXSIZE; data[left] = x; } void push_back(int x) { // 在队尾插入元素 if (isFull()) { cout << "Deque is full!" << endl; return; } data[right] = x; right = (right + 1) % MAXSIZE; } void pop_front() { // 在队头删除元素 if (isEmpty()) { cout << "Deque is empty!" << endl; return; } left = (left + 1) % MAXSIZE; } void pop_back() { // 在队尾删除元素 if (isEmpty()) { cout << "Deque is empty!" << endl; return; } right = (right - 1 + MAXSIZE) % MAXSIZE; } int front() { // 返回队头元素 if (isEmpty()) { cout << "Deque is empty!" << endl; return -1; } return data[left]; } int back() { // 返回队尾元素 if (isEmpty()) { cout << "Deque is empty!" << endl; return -1; } return data[(right - 1 + MAXSIZE) % MAXSIZE]; } }; int main() { Deque dq; dq.push_front(1); dq.push_back(2); dq.push_front(3); dq.push_back(4); cout << dq.front() << endl; // 输出:3 cout << dq.back() << endl; // 输出:4 dq.pop_front(); dq.pop_back(); cout << dq.front() << endl; // 输出:1 cout << dq.back() << endl; // 输出:2 return 0; } ``` 步骤: 1. 定义一个常量MAXSIZE,表示双端队列的最大长度。 2. 定义一个类Deque,包含数据存储数组data和左右指针left、right。 3. 构造函数初始化左右指针。 4. 定义isEmpty()和isFull()函数,分别判断队列是否为空和已满。 5. 定义push_front()和push_back()函数,在队头和队尾插入元素。 6. 定义pop_front()和pop_back()函数,在队头和队尾删除元素。 7. 定义front()和back()函数,分别返回队头和队尾元素。 8. 在main函数中创建Deque对象dq,测试双端队列的各种操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值