目录
1:容器适配器
- stack和queue有一点需要注意,虽然stack和queue也可以存放元素,但在STL中并没有将其划分在容器的行列,而是将其称为容器适配器,STL中stack和queue 默认使用deque.
- 在stack和queue的类模版声明中我们可以看到,它们的模版参数有两个,第一个是stack和queue当中所存储的元素类型,而另一个则是指定使用的容器类型,只不过当我们不指定使用何种容器的情况下,stack和queue默认使用deque作为容器.


2:stack的模拟实现
2.1:stack.h
cpp
#include <iostream>
using namespace std;
#include <deque>
namespace MyStack
{
template<class T, class Container = deque<T> >
class stack
{
public:
void push(const T& x);
void pop();
//自定义类型传值返回时会调用拷贝构造,所以传引用
T& top();
const T& top()const;
size_t size()const;
bool empty();
private:
Container _Container;
};
};
2.1.1:push和pop
栈的特点是后进先出,那么对于push我们可以调用容器适配器的push_back,由于是后进先出,那么pop调用的则是pop_back.
cpp
void push(const T& x)
{
//尾插
_Container.push_back(x);
}
void pop()
{
_Container.pop_back();
}
2.1.2:top和size以及empty
- 栈的top指的是栈顶元素,那么对应的则应该是容器适配器的back()函数,由于会存在const对象调用top函数,那么因此我们要对其进行函数重载.
- size和emtpy直接调用容器适配器的size()和empty函数即可.
cpp
const T& top()const
{
return _Container.back();
}
size_t size()const
{
return _Container.size();
}
bool empty()
{
return _Container.empty();
}
2.2:Test.cpp
cpp
#define _CRT_SECURE_NO_WARNINGS
#include "Stack.h"
#include <vector>
int main()
{
MyStack::stack<int,vector<int>> st1;
st1.push(1);
st1.push(2);
st1.push(3);
st1.push(4);
st1.push(5);
cout << "size:> " << st1.size() << endl;
while (!st1.empty())
{
cout << st1.top() << " ";
st1.pop();
}
return 0;
}

3:stack的总代码
3.1:stack.h
cpp
#include <iostream>
using namespace std;
#include <deque>
namespace MyStack
{
template<class T, class Container = deque<T> >
class stack
{
public:
void push(const T& x)
{
//尾插
_Container.push_back(x);
}
void pop()
{
_Container.pop_back();
}
//自定义类型传值返回时会调用拷贝构造,所以传引用
T& top()
{
return _Container.back();
}
const T& top()const
{
return _Container.back();
}
size_t size()const
{
return _Container.size();
}
bool empty()
{
return _Container.empty();
}
private:
Container _Container;
};
};
3.2:Test.cpp
cpp
#define _CRT_SECURE_NO_WARNINGS
#include "Stack.h"
#include <vector>
int main()
{
MyStack::stack<int,vector<int>> st1;
st1.push(1);
st1.push(2);
st1.push(3);
st1.push(4);
st1.push(5);
cout << "size:> " << st1.size() << endl;
while (!st1.empty())
{
cout << st1.top() << " ";
st1.pop();
}
return 0;
}
4:queue的模拟实现
4.1:quque.h
cpp
#include <iostream>
using namespace std;
#include <deque>
namespace MyQueue
{
template<class T, class Container = deque<T>>
class queue
{
public:
//尾插
void push(const T& value);
//头删
void pop();
//获取队尾元素
T& back();
T& back() const;
//获取队头元素
T& front();
T& front() const;
size_t size()const;
bool empty() const;
private:
Container _Container;
};
};
4.1.1:push和pop
队列的特点是先进先出,那么对于push我们可以调用容器适配器的push_back,由于是先进先出,那么pop调用的则是pop_front.
cpp
//尾插
void push(const T& value)
{
_Container.push_back(value);
}
//头删
void pop()
{
_Container.pop_front();
}
4.1.2:back和front和size与empty
- 队列的back指的是对头元素,那么对应的则应该是容器适配器的back()函数,由于会存在const对象调用back函数,那么因此我们要对其进行函数重载.队列的front指的是队尾元素,那么对应的则应该是容器适配器的front()函数,同理back函数我们也要对其进行函数重载.
- size和emtpy直接调用容器适配器的size()和empty函数即可.
4.2:Test.cpp
cpp
#define _CRT_SECURE_NO_WARNINGS
#include "Queue.h"
#include <list>
int main()
{
MyQueue::queue<int, list<int>> q1;
q1.push(1);
q1.push(2);
q1.push(3);
q1.push(4);
q1.push(5);
while (!q1.empty())
{
cout << q1.front() << "::" << q1.back() << endl;;
q1.pop();
}
return 0;
}

5:queue的总代码
5.1:Queue.h
cpp
#include <iostream>
using namespace std;
#include <deque>
namespace MyQueue
{
template<class T, class Container = deque<T>>
class queue
{
public:
//尾插
void push(const T& value)
{
_Container.push_back(value);
}
//头删
void pop()
{
_Container.pop_front();
}
//获取队尾元素
T& back()
{
return _Container.back();
}
T& back() const
{
return _Container.back();
}
//获取队头元素
T& front()
{
return _Container.front();
}
T& front() const
{
return _Container.front();
}
size_t size()const
{
return _Container.size();
}
bool empty() const
{
return _Container.empty();
}
private:
Container _Container;
};
};
5.2:Test.cpp
cpp
#define _CRT_SECURE_NO_WARNINGS
#include "Queue.h"
#include <list>
int main()
{
MyQueue::queue<int, list<int>> q1;
q1.push(1);
q1.push(2);
q1.push(3);
q1.push(4);
q1.push(5);
while (!q1.empty())
{
cout << q1.front() << "::" << q1.back() << endl;
q1.pop();
}
return 0;
}
6:priority_queue的模拟实现
6.1:priority_queue.h
cpp
#pragma once
#include <iostream>
using namespace std;
#include <assert.h>
#include <vector>
#include <algorithm>
namespace MyPriorityQueue
{
template <class T,class Container = vector<T>,class Compare = less<T>>
class priority_queue
{
public:
void Adjust_Up(int child);
void Adjust_Down(int parent);
void push(const T& val);
void pop();
bool empty() const;
size_t size() const;
T& top();
private:
Container _Container;
};
}
6.1.1:向上调整算法
- 将目标节点与其父节点进行比较.
- 若目标节点的值比父节点大,则进行交换,并且同时将原目标节点的父亲节点当作新的目标节点进行向上调整,若目标结点的值比其父结点的值小,则停止向上调整,此时该树已经是大堆了.
cpp
void Adjust_Up(int child)
{
//找到目标节点的父亲节点
int parent = (child - 1) / 2;
while(child > 0)
{
//孩子比父亲大,进行交换
if(_Container[child] > _Container[parent])
{
swap(_Container[child],_Container[parent]);
//更新孩子和父亲,继续进行向上调整
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
6.1.2:向下调整算法
使用向下调整算法有一个前提:
- 若想将其调整为小堆 ,那么根结点的左右子树必须都为小堆。
- 若想将其调整为大堆 ,那么根结点的左右子树必须都为大堆。
- 从根节点开始,选出左右孩子中的最大值.
- 让最大的孩子与父亲进行比较 .
- 若孩子比父亲大,则让该孩子的与其父亲的位置进行交换.并将原来大的孩子的位置当成父亲继续向下进行调整,直到调整到叶子结点为止
- 若若大的孩子比父亲小,则不需处理了,调整完成,整个树已经是大堆了.
cpp
void Adjust_Down(int parent)
{
//假设左孩子最大
int child = parent * 2 + 1;
while (child < size())
{
if(child + 1 < size() && _Container[child + 1] > _Container[child])
{
child++;
}
//孩子比父亲大,进行交换
if (_Container[child] > _Container[parent])
{
swap(_Container[child], _Container[parent]);
//更新孩子和父亲,继续进行向下调整
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
6.1.3:push和pop
- 对于push,直接尾插,然后进行向上调整算法即可.
- 对于pop,删除的是堆顶的元素,但是这个删除过程可并不是直接删除堆顶的数据,而是先将堆顶的数据与最后一个结点的位置交换,然后再删除最后一个结点,再对堆进行一次向下调整.若是直接删除堆顶的数据,那么原堆后面数据的父子关系就全部打乱了,需要全体重新建堆,时间复杂度为O(N)。若是用上述方法,那么只需要对堆进行一次向下调整即可,因为此时根结点的左右子树都是小堆,我们只需要在根结点处进行一次向下调整即可,时间复杂度为O(log(N)).
cpp
void push(const T& val)
{
//尾插
_Container.push_back(val);
//向上调整
Adjust_Up(size() - 1);
}
void pop()
{
//交换堆顶和堆底
swap(_Container[0], _Container[size() - 1]);
//尾删
_Container.pop_back();
//向下调整
Adjust_Down(0);
}
6.1.4:empty与size与top
cpp
bool empty() const
{
return _Container.empty();
}
size_t size() const
{
return _Container.size();
}
T& top()
{
return _Container[0];
}
6.2:Test.cpp
cpp
#include "Priority_queue.h"
int main()
{
MyPriorityQueue::priority_queue<int> pq;
pq.push(70);
pq.push(56);
pq.push(30);
pq.push(15);
pq.push(25);
pq.push(10);
pq.push(90);
pq.push(100);
while(!pq.empty())
{
cout << pq.top() << " " << "size:>" << pq.size() << endl;
pq.pop();
}
return 0;
}

7:priority_queue的总代码
7.1priority_queue.h
cpp
#pragma once
#include <iostream>
using namespace std;
#include <assert.h>
#include <vector>
#include <algorithm>
namespace MyPriorityQueue
{
template <class T,class Container = vector<T>,class Compare = less<T>>
class priority_queue
{
public:
void Adjust_Up(int child)
{
//找到目标节点的父亲节点
int parent = (child - 1) / 2;
while(child > 0)
{
//孩子比父亲大,进行交换
if(_Container[child] > _Container[parent])
{
swap(_Container[child],_Container[parent]);
//更新孩子和父亲,继续进行向上调整
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void Adjust_Down(int parent)
{
//假设左孩子最大
int child = parent * 2 + 1;
while (child < size())
{
if(child + 1 < size() && _Container[child + 1] > _Container[child])
{
child++;
}
//孩子比父亲大,进行交换
if (_Container[child] > _Container[parent])
{
swap(_Container[child], _Container[parent]);
//更新孩子和父亲,继续进行向下调整
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void push(const T& val)
{
//尾插
_Container.push_back(val);
//向上调整
Adjust_Up(size() - 1);
}
void pop()
{
//交换堆顶和堆底
swap(_Container[0], _Container[size() - 1]);
//尾删
_Container.pop_back();
//向下调整
Adjust_Down(0);
}
bool empty() const
{
return _Container.empty();
}
size_t size() const
{
return _Container.size();
}
T& top()
{
return _Container[0];
}
private:
Container _Container;
};
}
7.2:Test.cpp
cpp
#include "Priority_queue.h"
int main()
{
MyPriorityQueue::priority_queue<int> pq;
pq.push(70);
pq.push(56);
pq.push(30);
pq.push(15);
pq.push(25);
pq.push(10);
pq.push(90);
pq.push(100);
while(!pq.empty())
{
cout << pq.top() << " " << "size:>" << pq.size() << endl;
pq.pop();
}
return 0;
}
8:反向迭代器
反向迭代器与正向迭代器的区别主要在遍历的方向上:正向跌代器是从容器的第一个元素开始向后遍历的,反向迭代器是从容器的最后一个元素开始向前遍历的.因此我们可以通过对正向迭代器的封装来生成反向迭代器----迭代器适配器.

反向迭代器在实现的时候与正向迭代器是一种镜像对称的关系.

使用正向迭代器适配反向迭代器的时候会认为它两存在对称关系,那么此时就会导致两个问题
- rbegin第一次解引用是一个随机值.
- rbegin == rend就结束了
那么就导致了第一个元素没有取到,那么我们该如何解决这个对称的坑呢
- 通过解引用来解决这个坑,解引用时,我们并不是解引用当前位置,而是解引用它的前一个位置!

反向迭代器的++是正向迭代器的--,反向迭代器的--就是正向迭代器的++.

8.1:代码实现
cpp
#define _CRT_SECURE_NO_WARNINGS
namespace MyReverseIterator
{
template<class Iterator,class Reference,class Pointer>
class ReverseIterator
{
typedef ReverseIterator<Iterator, Reference, Pointer> Self;
ReverseIterator(Iterator it)
:_it(it)
{
};
Self& operator++()
{
--_it;
return *this;
}
Self& operator--()
{
++_it;
return *this;
}
Reference operator*()
{
/*
* 正向迭代器与反向迭代器成一个镜像对称的关系,所以反向迭代器解引用时的元素不是解引用当前位置
* 而是解引用它的前一个位置
* 因为解引用是不能够影响当前迭代器的,所以需要创建一个临时变量
*/
Iterator temp = _it;
--temp;
return *temp;
}
Pointer operator->()
{
return &(operator*())
}
bool operator!=(const Self& rit)
{
return _it != rit._it;
}
bool operator==(const Self& rit)
{
return _it == rit._it;
}
private:
Iterator _it;
};
}
8.2:反向迭代器的应用
我们用list的正向迭代器生成list的反向迭代器为例.
8.2.1:ReverseInterator.h
cpp
#pragma once
#define _CRT_SECURE_NO_WARNINGS
namespace MyReverseIterator
{
template<class Iterator, class Reference, class Pointer>
struct ReverseIterator
{
typedef ReverseIterator<Iterator, Reference, Pointer> Self;
Iterator _it;
ReverseIterator(Iterator it)
:_it(it)
{
};
Self& operator++()
{
--_it;
return *this;
}
Self& operator--()
{
++_it;
return *this;
}
Reference operator*()
{
/*
* 正向迭代器与反向迭代器成一个镜像对称的关系,所以反向迭代器解引用时的元素不是解引用当前位置
* 而是解引用它的前一个位置
* 因为解引用是不能够影响当前迭代器的,所以需要创建一个临时变量
*/
Iterator temp = _it;
--temp;
return *temp;
}
Pointer operator->()
{
return &(operator*());
}
bool operator!=(const Self& rit)
{
return _it != rit._it;
}
bool operator==(const Self& rit)
{
return _it == rit._it;
}
};
};
8.2.2:List.h
cpp
#pragma once
#include <iostream>
using namespace std;
#include <assert.h>
#include <string>
#include "ReverseInterator.h"
namespace MyList
{
//节点类的定义
template <class T>
struct ListNode
{
ListNode* Previous;
ListNode* Next;
T Val;
//构造函数
ListNode(const T& val = T())
:Previous(nullptr)
, Next(nullptr)
, Val(val)
{
}
};
//迭代器类的定义
template <class T, class Reference, class Pointer>
struct ListIterator
{
typedef ListNode<T> Node;
typedef ListIterator<T, Reference, Pointer> Self;
//构造函数
ListIterator(Node* node)
:_Node(node)
{
};
Node* _Node;
//前置++
Self& operator++()
{
_Node = _Node->Next;
return *this;
}
//后置++
Self operator++(int)
{
//拷贝一个临时变量
Self temp = *this;
_Node = _Node->Next;
return temp;
}
//前置--
Self& operator--()
{
_Node = _Node->Previous;
return *this;
}
//后置--
Self operator--(int)
{
//拷贝一个临时变量
Self temp = *this;
_Node = _Node->Previous;
return temp;
}
Reference operator*()
{
return _Node->Val;
}
Pointer operator->()
{
return &_Node->Val;
}
bool operator!=(const Self& it)
{
//通过比较节点地址来判断迭代器是否相等
return _Node != it._Node;
}
bool operator==(const Self& it)
{
return _Node == it._Node;
}
};
//template <class T>
//struct ListConstIterator
//{
// typedef ListNode<T> Node;
// typedef ListConstIterator<T> Self;
// //构造函数
// ListConstIterator(Node* node)
// :_Node(node)
// {
// };
// Node* _Node;
// //前置++
// Self& operator++()
// {
// _Node = _Node->Next;
// return *this;
// }
// //后置++
// Self operator++(int)
// {
// //拷贝一个临时变量
// Self temp = *this;
// _Node = _Node->Next;
// return temp;
// }
// //前置--
// Self& operator--()
// {
// _Node = _Node->Previous;
// return *this;
// }
// //后置--
// Self operator--(int)
// {
// //拷贝一个临时变量
// Self temp = *this;
// _Node = _Node->Previous;
// return temp;
// }
// const T& operator*()
// {
// return _Node->Val;
// }
// const T* operator->()
// {
// return &_Node->Val;
// }
// bool operator!=(const Self& it)
// {
// //通过比较节点地址来判断迭代器是否相等
// return _Node != it._Node;
// }
// bool operator==(const Self& it)
// {
// return _Node == it._Node;
// }
//};
template <class T>
class List
{
typedef ListNode<T> Node;
public:
typedef ListIterator<T, T&, T*> iterator;
typedef ListIterator<T, const T&, const T*> const_iterator;
typedef MyReverseIterator::ReverseIterator<iterator, T&, T*> reverse_iterator;
typedef MyReverseIterator::ReverseIterator<iterator, const T&, const T*> const_reverse_iterator;
public:
void Empty_Init()
{
//创建哨兵位的头节点
_Head = new Node();
_Head->Next = _Head;
_Head->Previous = _Head;
_Size = 0;
}
List()
{
Empty_Init();
}
//拷贝构造函数
//lt2(lt1); lt1不变,lt2和lt1内容相同
List(const List<T>& lt)
{
Empty_Init();
for (auto& element : lt)
{
push_back(element);
}
}
reverse_iterator rbegin()
{
return reverse_iterator(end());
}
reverse_iterator rend()
{
return reverse_iterator(begin());
}
const_reverse_iterator rbegin() const
{
return const_reverse_iterator(end());
}
const_reverse_iterator rend() const
{
return const_reverse_iterator(begin());
}
iterator begin()
{
//返回第一个有效节点
return iterator(_Head->Next);
}
iterator end()
{
//返回哨兵位节点
return iterator(_Head);
}
const_iterator begin() const
{
//返回第一个有效节点
return _Head->Next;
}
const_iterator end() const
{
//返回哨兵位节点
return _Head;
}
void push_back(const T& Val)
{
////构建新节点
//Node* NewNode = new Node(Val);
////找到尾节点
//Node* Tail = _Head->Previous;
////1:尾结点的Next指针指向NewNode
//Tail->Next = NewNode;
////2:NewNode的前驱节点指向Tail
//NewNode->Previous = Tail;
////3 : NewNode的后驱节点指向哨兵位
//NewNode->Next = _Head;
////4:哨兵位的前驱节点指向NewNode
//_Head->Previous = NewNode;
insert(end(), Val);
}
void pop_back()
{
erase(--end());
}
void push_front(const T& Val)
{
insert(begin(), Val);
}
void pop_front()
{
erase(begin());
}
void insert(iterator Position, const T& Val)
{
//构建新节点
Node* NewNode = new Node(Val);
//找到Position位置的节点
Node* Current = Position._Node;
//找到Position位置节点的前驱节点
Node* Prev = Current->Previous;
//当前节点的前驱指向NewNode
Prev->Next = NewNode;
//NewNode的前驱指向Prev
NewNode->Previous = Prev;
//NewNode的后驱指向Current
NewNode->Next = Current;
//Current的前驱指向NewNode
Current->Previous = NewNode;
_Size++;
}
iterator erase(iterator Position)
{
//找到Position位置的节点
Node* Current = Position._Node;
//找到Position位置节点的前驱节点
Node* Prev = Current->Previous;
//找到Position位置节点的后继节点
Node* Next = Current->Next;
//当前节点的前驱节点的后继指向当前节点后继节点
Prev->Next = Next;
//当前节点的后继节点的前驱指向当前节点前驱节点
Next->Previous = Prev;
//释放当前节点
delete Current;
_Size--;
return iterator(Next);
}
size_t size()
{
return _Size;
}
bool empty()
{
return _Size == 0;
}
void clear()
{
iterator it = begin();
while (it != end())
{
it = erase(it);
}
}
void swap(List<T>& lt)
{
std::swap(_Head, lt._Head);
std::swap(_Size, lt._Size);
}
List<T>& operator=(List<T> lt)
{
swap(lt);
return *this;
}
~List()
{
clear();
delete _Head;
_Head = nullptr;
}
private:
Node* _Head;
size_t _Size;
};
}
8.2.3:Test.cpp
cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <vector>
#include "List.h"
void TestList12()
{
MyList::List<int> lt;
lt.push_back(10);
lt.push_back(20);
lt.push_back(30);
lt.push_back(40);
lt.push_back(50);
MyList::List<int>::reverse_iterator rit = lt.rbegin();
while (rit != lt.rend())
{
cout << *rit << " ";
++rit;
}
cout << endl;
}
void TestList13()
{
MyList::List <A> lt;
A aa1(1, 1);
lt.push_back(aa1);
lt.push_back(aa1);
lt.push_back(A(2, 2));
lt.push_back({ 3,3 });
lt.push_back({ 4,4 });
MyList::List <A>::reverse_iterator rit = lt.rbegin();
while (rit != lt.rend())
{
//cout << (*it)._a1 << ":" << (*it)._a2 << endl;
//ʡ汾
cout << rit->_a1 << ":" << rit->_a2 << endl;
//汾
//cout << it.operator->()->_a1 <<" "<< it.operator->()->_a2 << endl;
++rit;
}
cout << endl;
}
int main()
{
TestList12();
cout << endl;
TestList13();
return 0;
}

