杂谈 · list实现栈与队列的发现

目录

前言

一、目标

二、分析

三、总结


前言

        栈与队列在STL库中类属容器适配器,是通过list进行实现的。最近回顾栈与队列的实现原理时,有这样的发现:

        栈中添加栈顶元素(push()方法),其实现逻辑是通过list的push_front()方法

        栈中删除栈顶元素(pop()方法)  ,其实现逻辑是通过list的pop_front()方法

        队列中添加尾元素(push()方法),其实现逻辑是通过list的push_back()方法

        队列中删除头元素(pop()方法)  ,其实现逻辑是通过list的pop_front()方法

那为何要选择这几个list的功能函数,是否是唯一的实现方法呢?


一、目标

        通过对list功能函数的分析和对栈与队列性质的回顾,本篇将进一步探索栈与队列的实现方法是否唯一,以及选择的合理性

二、分析

        我们先来看一下list的增删的几个功能函数(常用):

函数名 作用
pop_back() 删除最后一个元素
pop_front() 删除第一个元素

push_back()

在list的末尾添加一个元素
push_front() 在list的头部添加一个元素

        所以,头尾都可以进行增删操作。

        我们再来看一下,栈与队列的性质:

名称 性质
栈(stack) 先进后出
队列(queue) 先进先出

        根据性质,实现的功能仅需要满足在头尾同一端进行增删,实现队列的功能仅需要满足在不同一端进行增删。所以我们可以得出第一个结论:

结论1:栈与队列的实现方法不唯一

        那么为何不选用pop_back()的功能函数呢,是随意选择还是另有原因呢?

        首先我们创建一个自己编写的List类(部分功能)

class List
{
public:
	List();
	~List();
	void push_back(const int& val); // 从尾部插入元素
	void push_front(const int& val); // 从尾部插入元素
	void pop_back();				// 从尾部删除
	void pop_front();				// 从头部删除
	void print();					// 打印链表中的数据
	bool empty() const;				// 判断为空
	void clear();
	void remove(const int& val);
	void unique();
	void swap(List& lst);
	void reverse();
	void merge(List& lst);
	void sort();
	int size();
	// bool isOrder(); // 判断链表是否有序(升序)
// 迭代器
	Iterator begin();			  // begin:返回指向头结点的迭代器
	Iterator end();				  // end:返回指向辅助尾结点的迭代器
	Iterator erase(Iterator pos); // erase
	Iterator erase(Iterator start, Iterator end);
	Iterator insert(Iterator pos, const int& val);
	void splice(Iterator pos, List& lst); // splice// 清空lst链表
private:
	Node* pHead; // 指向辅助头(不存储数据)结点的指针
	Node* pRear; // 指向辅助尾(不存储数据)结点的指针

};

             部分功能实现:

void List::push_back(const int& val) // 从尾部插入元素
{
	if (!pHead)
	{
		pHead = pRear = new Node(val);
	}
	else
	{
		Node* temp = new Node(val);
		pRear->pNext = temp;
		temp->pFront = pRear;
		pRear = temp;
	}
}
void List::push_front(const int& val) // 从头部插入元素
{
	if (!pHead)
	{
		pHead = pRear = new Node(val);
	}
	else
	{
		Node* temp = new Node(val);
		temp->pNext = pHead;
		pHead->pFront = temp;
		pHead = temp;
	}
}
void List::pop_back()				// 从尾部删除
{
	erase(pRear);
}
void List::pop_front()				// 从头部删除
{
	erase(pHead);
}
Iterator List::erase(Iterator pos) // erase
{
	if (pos == begin())
	{
		Node* del = pos.pNode;
		pHead = pos.pNode->pNext;
		++pos;
		delete del;
		del = nullptr;
		return pos;
	}
	else
	{
		Iterator it = begin();
		while (it.pNode->pNext != pos.pNode)
		{
			++it;
		}
		Node* cur = it.pNode, * del = pos.pNode;
		cur->pNext = del->pNext;
		++pos;
		delete del;
		del = nullptr;
		return pos;
	}
}

         不难发现调用pop_back()这个功能函数,需要遍历整个链表,效率远低于pop_front()。所以我们可以得出第二个结论:

结论2:由于pop_back()的效率远低于pop_front(),故我们不选择删尾这种情况

三、总结

        综上,我们证明了通过list实现栈与队列的增删的方法不唯一,但是我们也不是随意选择实现方法。从效率角度考虑,pop_back()的效率远低于pop_front()。所以我们才选择如下的功能方法。

名称 实现逻辑 实现逻辑
栈(stack) 添加栈顶元素 push_front()
删除栈顶元素 pop_front()
队列(queue) 添加尾元素 push_back()
删除头元素 pop_front()

猜你喜欢

转载自blog.csdn.net/H_Greddy/article/details/126616847