一个基于双向链表的队列实现

引言

在数据结构的学习与实践中,队列是一种常见的线性,表遵循先进先出(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)

提供 frontback 成员函数,分别返回队头和队尾元素的引用,方便用户获取队列首尾元素的值,以便进行相应的操作或判断。

判空与大小(empty 和 size)

empty 函数用于判断队列是否为空,通过比较头节点的后继是否指向自身来快速得出结果;size 函数返回队列的容量 cap,使用户能够了解队列元素中的数量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值