目录
前言
栈与队列在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() |