💗个人主页💗
⭐个人专栏——C++学习⭐
💫点击关注🤩一起学习C语言💯💫
目录
导读
1. stack和queue的底层
1.1 stack
1.2 queue
2. 什么是适配器
3. 常见适配器
4. stack具体实现
4.1 成员变量
4.2 push函数
4.3 pop函数
4.4 size函数
4.5 empty函数
4.6 top函数
5. stack实现完整代码
5.1 stack.h
5.2 test.cpp
6. queue具体实现
6.1 成员变量
6.2 push函数
6.3 pop函数
6.4 size函数
6.5 empty函数
6.6 front和back函数
7. queue实现完整代码
7.1 queue.h
7.2 test.cpp
导读
我们上次了解了stack和queue的一些基本使用,今天我们就来试着实现一下。
1. stack和queue的底层
1.1 stack
C++中的stack通常是由deque(双端队列)或vector(动态数组)实现的。这是因为deque和vector都提供了方便的尾部插入和删除操作,符合stack的后进先出(LIFO)原则。
- 如果使用deque实现stack,那么每次将元素推入栈顶时,将元素插入到deque的尾部;而每次从栈顶弹出元素时,从deque的尾部删除元素。这样可以快速实现栈的操作,并保持栈的后进先出的特性。
- 如果使用vector实现stack,那么每次将元素推入栈顶时,将元素插入到vector的尾部;而每次从栈顶弹出元素时,从vector的尾部删除元素。类似地,这样也可以实现栈的操作,但由于vector是动态数组,所以在元素数量超过vector的当前容量时,可能需要重新分配内存并复制元素,这可能导致性能损失。
C++的标准库中还提供了适配器(adapter)stack,它基于deque或vector实现,隐藏了底层容器的实现细节,并提供了方便的栈操作接口。这样可以在不直接操作底层容器的情况下使用stack,使代码更加简洁和易读。
需要注意的是,由于stack只提供了后进先出的操作,没有提供随机访问元素的能力,因此不支持迭代器遍历。如果需要遍历栈中的元素,可以通过反复弹出栈顶元素并处理,直到栈为空。
1.2 queue
queue
是一个基于适配器模式实现的容器适配器。它是一个先进先出(FIFO)的数据结构,内部使用一个底层容器来存储元素。
默认情况下,queue
使用deque
作为其底层容器。deque
是一种双向队列,支持快速在头部和尾部进行插入和删除操作,因此适合作为queue
的底层容器。
通过适配器的方式,
queue
将底层容器的接口封装起来,提供了一组符合先进先出原则的操作。这使得使用queue
变得更加方便、简洁,并且可以灵活地选择底层容器类型,以满足特定的需求。如果需要自定义底层容器,可以通过模板参数来指定特定的容器类型。
2. 什么是适配器
适配器(Adapter)是一种设计模式,用于将一个类的接口转换为客户端所期望的另一个接口。适配器模式允许原本不兼容的类能够一起工作。
适配器通常有两种类型:
- 类适配器:使用多重继承的方式,将被适配类的接口转换为目标接口。适配器继承被适配类,并实现目标接口。
- 对象适配器:通过组合的方式,将适配器对象与被适配对象关联起来,将被适配类的接口转换为目标接口。适配器实现目标接口,并在内部持有被适配对象的实例。
适配器模式常用于以下情况:
- 当需要使用一个已经存在的类,但其接口与现有代码不兼容时,可以使用适配器模式将其接口转换为目标接口。
- 当需要复用一些现有类,但是这些类不具备与所需接口匹配的方法时,可以使用适配器模式添加额外的逻辑,实现所需接口。
总结来说,适配器模式可以让原本不兼容的类能够一起工作,实现接口转换和兼容性。
3. 常见适配器
以下是C++中的一些常见适配器:
-
stack:适配器stack用于将deque或vector等底层容器实现为后进先出(LIFO)的栈。
-
queue:适配器queue用于将deque或list等底层容器实现为先进先出(FIFO)的队列。
-
priority_queue:适配器priority_queue用于将vector或deque等底层容器实现为优先级队列,其中元素按照一定的优先级顺序排列。
-
stack和queue的适配器:C++标准库还提供了两个适配器,即stack和queue,它们可以使用deque、list或vector等底层容器作为实现。这样可以根据需求选择不同的底层容器,以满足不同的性能要求。
这些适配器通过封装底层容器的实现,提供了一种统一的接口,使得程序员可以方便地使用这些数据结构和算法,而不需要关心底层容器的具体实现细节。此外,适配器还提供了简化和抽象的功能,使得代码更加易读和可维护。
4. stack具体实现
4.1 成员变量
//第二个模板参数给一个缺省值(只能从右往左给)
template<class T, class Container = vector<T>>
class stack
{
private:
Container _con;
};
Container
表示用于存储栈元素的容器类型,默认情况下使用vector<T>
作为容器类型。可以通过实例化stack
类时指定具体的容器类型。通过使用模板类
stack
,可以实例化不同类型元素的栈,并且可以灵活选择底层容器类型。例如,可以创建一个存储整数类型的栈:stack<int>
,默认使用vector<int>
作为容器。也可以创建一个存储字符串类型的栈:stack<string, list<string>>
,使用list<string>
作为容器。
4.2 push函数
void push(const T& x)
{
_con.push_back(x);
}
具体来说,这个函数使用了
_con
容器的push_back()
成员函数,将元素x
插入到容器的尾部。每次调用
push()
函数,新元素都会被添加到底层容器的尾部,实现了栈的特性:后进先出(LIFO)。
4.3 pop函数
void pop()
{
_con.pop_back();
}
pop
函数使用了底层容器_con
的pop_back()
成员函数,它会从底层容器的末尾弹出一个元素。
4.4 size函数
size_t size()
{
return _con.size();
}
这个函数使用了
_con
容器的size()
成员函数,它会返回底层容器的元素个数。
4.5 empty函数
bool empty()
{
return _con.empty();
}
这是
stack
类中的empty
函数的实现。它执行的操作是判断底层容器是否为空。具体来说,这个函数使用了
_con
容器的empty()
成员函数,它会检查底层容器是否为空。如果底层容器为空,返回true
,否则返回false
。
4.6 top函数
const T& top()
{
return _con.back();
}
top
函数使用了底层容器_con
的back()
成员函数,它返回底层容器中的最后一个元素,即栈中的顶部元素。
5. stack实现完整代码
5.1 stack.h
#pragma once
#include <iostream>
using namespace std;
#include <vector>
namespace Mystack
{
//第二个模板参数给一个缺省值(只能从右往左给)
template<class T, class Container = vector<T>>
class stack
{
public:
void push(const T& x)
{
_con.push_back(x);
}
void pop()
{
_con.pop_back();
}
size_t size()
{
return _con.size();
}
bool empty()
{
return _con.empty();
}
const T& top()
{
return _con.back();
}
private:
Container _con;
};
}
5.2 test.cpp
#include "stack.h"
void test_stack()
{
Mystack::stack<int> st;
st.push(1);
st.push(2);
st.push(3);
st.push(4);
while (!st.empty())
{
cout << st.top() << " ";
st.pop();
}
cout << endl;
}
int main()
{
test_stack();
return 0;
}
6. queue具体实现
6.1 成员变量
template<class T, class Container = deque<T>>
class queue
{
private:
Container _con;
};
这是一个queue类的模板定义。它使用一个模板参数T来表示元素的类型,并使用一个模板参数Container来表示底层容器的类型,默认为deque<T>。
在这个queue类中,私有成员变量_con表示底层容器,用于存储元素。它的类型是通过模板参数Container来确定的,默认情况下是deque<T>类型。
这个模板类定义了一个基本的队列数据结构,使得用户可以方便地在底层容器上进行队列操作,例如入队、出队、获取队头元素等。具体的队列操作实现可以通过对底层容器的操作来完成。
6.2 push函数
void push(const T& x)
{
_con.push_back(x);
}
这个函数使用了
_con
容器的push_back()
成员函数,将元素x
插入到容器的尾部。在deque
容器中,push_back()
函数的时间复杂度为常数时间,可以快速地将元素添加到容器的尾部。
6.3 pop函数
void pop()
{
_con.pop_front();
}
这个函数使用了
_con
容器的pop_front()
成员函数,它会删除底层容器的第一个元素。在deque
容器中,pop_front()
函数的时间复杂度为常数时间,因此可以快速地删除第一个元素。
6.4 size函数
size_t size()
{
return _con.size();
}
这是
queue
类中的size
函数的实现。它执行的操作是返回底层容器的元素个数。具体来说,这个函数使用了
_con
容器的size()
成员函数,它会返回底层容器的元素个数。在deque
容器中,size()
函数的时间复杂度为常数时间,因此可以快速地获取元素个数。
6.5 empty函数
bool empty()
{
return _con.empty();
}
这是
queue
类中的empty
函数的实现。它执行的操作是判断底层容器是否为空。具体来说,这个函数使用了
_con
容器的empty()
成员函数,它会检查底层容器是否为空。如果底层容器为空,返回true
,否则返回false
。
6.6 front和back函数
const T& front()
{
return _con.front();
}
const T& back()
{
return _con.back();
}
这是
queue
类中的front
和back
函数的实现。它们分别返回队列的第一个元素和最后一个元素的引用。具体来说,
front
函数使用了底层容器_con
的front()
成员函数,它会返回底层容器的第一个元素的引用。back
函数则使用了_con
的back()
成员函数,它返回底层容器的最后一个元素的引用。这样,可以通过调用
front()
和back()
函数来访问队列的第一个元素和最后一个元素,而不需要直接操作底层容器。
7. queue实现完整代码
7.1 queue.h
#pragma once
#include <iostream>
using namespace std;
#include<deque>
namespace Myqueue
{
template<class T, class Container = deque<T>>
class queue
{
public:
void push(const T& x)
{
_con.push_back(x);
}
void pop()
{
_con.pop_front();
}
size_t size()
{
return _con.size();
}
bool empty()
{
return _con.empty();
}
const T& front()
{
return _con.front();
}
const T& back()
{
return _con.back();
}
private:
Container _con;
};
}
7.2 test.cpp
#include "queue.h"
void test_queue1()
{
Myqueue::queue<int> q;
q.push(1);
q.push(2);
cout << q.front() << " ";
q.pop();
q.push(3);
q.push(4);
while (!q.empty())
{
cout << q.front() << " ";
q.pop();
}
cout << endl;
}
int main()
{
test_queue1();
return 0;
}