引言
在数据结构的学习与实践中,队列是一种常见的线性,表遵循先进先出(FIFO)的原则。今天,我想和大家分享一个基于双向链表实现的队列类,它具有高效的元素插入和删除操作,适用于多种应用场景。
队列类的设计
这个队列类 list_Queue
采用了模板机制,使其能够处理不同数据类型,具有较强的通用性。它包含以下关键组成部分:
节点结构
定义了一个 Node 结
构体,每个节点包含数据域 Data
,以及指向下一个节点的指针 next
和指向前一个节点的指针 pre
,这种双向链表的结构为队列元素的快速插入和删除提供了便利。
成员变量
-
``head:头节点,用于标记队列的起始位置,简化了队列操作的逻辑。
-
cap
:记录队列中元素的数量,方便用户快速获取队列的大小。
构造函数与析构函数
-
构造函数初始化队列,创建头节点,并将其前后指针指向自身,表示一个空队列。
-
析构函数负责释放队列中所有节点的内存,避免内存泄漏,确保程序的健壮性。
深拷贝构造函数
深拷贝构造函数避免了浅拷贝可能导致的潜在问题,如多个对象共享同一块内存,引发数据错误或异常。它通过逐个复制原队列中的节点,构建一个新的独立队列,保障了数据的安全性和完整性。
赋值运算符重载
同样采用深拷贝 + 交换的方式,先创建一个临时队列对象的副本,然后与当前对象交换数据,实现在赋值操作中对对象的正确更新,同时避免了自我赋值等异常情况。
#include<iostream>
#include<algorithm>
using namespace std;
template<class T>
class list_Queue
{
public:
list_Queue()//构造函数
{
head = new Node;
head->next = head;
head->pre = head;
cap = 0;
}
list_Queue(const list_Queue& other)//深拷贝
{
head = new Node;
head->next = head;
head->pre = head;
Node* other_p = other.head->next;
while (other_p != other.head)
{
Node* next_p = new Node;
next_p->Data = other_p->Data;
next_p->next = head;
next_p->pre = head->pre;
head->pre->next = next_p;
head->pre = next_p;
other_p = other_p->next;
}
this->cap = other.cap;
}
~list_Queue()//析构函数
{
Node* p = head->next;
while (p != head)
{
Node* next_p = p->next;
delete p;
p = next_p;
}
delete head;
head = nullptr;
}
list_Queue& operator=(const list_Queue& other);
void clear() {
while (!empty()) {
pop();
}
}
void push(T val)//入队
{
Node* p = new Node;
p->Data = val;
p->next = head;
p->pre = head->pre;
head->pre->next = p;
head->pre = p;
cap++;
}
void pop()//出队
{
if (head->next == head)throw"错误";
Node* p = head->next;
p->next->pre = head;
head->next = p->next;
delete p;
cap--;
}
T& front()//取队头
{
if (head->next == head)throw"错误";
return head->next->Data;
}
T& back()//取队尾
{
if (head->pre == head)throw"错误";
return head->pre->Data;
}
bool empty()//判空
{
if (head->next == head)return true;
else return false;
}
int size()//大小
{
return cap;
}
private:
struct Node
{
Node(T val = T()) :Data(val), next(nullptr), pre(nullptr) {};
T Data;
Node* next;
Node* pre;
};
Node* head;//头节点
int cap;//大小
};
template<class T>
list_Queue<T>& list_Queue<T>::operator=(const list_Queue& other)//深拷贝+交换
{
if (&other == this)return *this;
list_Queue temp(other);
std::swap(head, temp.head);
std::swap(cap, temp.cap);
return *this;
}
队列的基本操作
入队(push)
当有新元素需要入队时,创建一个新的节点,将其插入到队列的尾部,通过调整尾部节点的指针关系,使得新节点成为队列尾的新部,同时增加队列的容量计数。
出队(pop)
出队操作从队列头部移除元素,首先检查队列是否为空,若不为空则调整头节点的指针,跳过原来的队头节点,并释放该节点的内存,同时减少队列容量计数。
访问队头和队尾元素(front 和 back)
提供 front
和 back
成员函数,分别返回队头和队尾元素的引用,方便用户获取队列首尾元素的值,以便进行相应的操作或判断。
判空与大小(empty 和 size)
empty
函数用于判断队列是否为空,通过比较头节点的后继是否指向自身来快速得出结果;size
函数返回队列的容量 cap
,使用户能够了解队列元素中的数量。