stack--容器适配器
注意容器适配器本身是没有迭代器的,所以也不支持C11中的基于范围的for循环。
stack容器接口测试:
#include<iostream>
#include<stack>
using namespace std;
void test01()
{
stack<int> st;
for (int i = 0; i < 10; ++i)
st.push(i);
cout << st.size() << endl;
//for (auto& e : st)//栈没有办法通过迭代器访问
//{
// cout << e << endl;
//}
//stack<int>::iterator;//stack是容器适配器,不包含迭代器,所以不支持c11基于范围的for循环
while (!st.empty())
{
cout << st.top() << " ";
st.pop();
}
cout << endl;
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
for (const auto& e : arr)//内置类型底层指针可以充当迭代器所以,所以可以使用基于范围的for循环
{
cout << e << " ";
}
cout << endl;
}
void main()
{
test01();
system("pause");
}
stack模拟实现
#include<iostream>
#include<list>
#include<vector>
#include<assert.h>
#include<deque>
using namespace std;
namespace hym
{
template<class T,class cont=deque<T>>//默认的类型参数-底层适配器是双端队列
class stack
{
public:
stack()
{
/*capacity = STACK_DEFAULT_SIZE;
tp = 0;
base = new T[capacity];*/
}
size_t size() const
{//return tp;
return _C.size();
}
bool empty() const
{//return tp == 0;
return _C.empty();
}
T& top()
{
/*assert(tp != 0);
return base[tp - 1];*/
return _C.back();
}
const T& top() const
{
/*assert(tp != 0);
return base[tp - 1];*/
return _C.back();
}
void push(const T& x)
{
//if (tp >= capacity)
//{
// //扩容;
//}
//base[tp] = x;
//tp++;
_C.push_back(x);
}
void pop()
{
/*assert(base != NULL);
tp--;*/
_C.pop_back();
}
~stack()
{
/*delete[] base;
capacity = 0;
tp = 0;*/
}
private:
/*enum {STACK_DEFAULT_SIZE=8};
T* base;
size_t capacity;
size_t tp;*///原生态写法
//list<T> _C;
cont _C;
};
queue-容器适配器
queue接口测试
队列不包含迭代器,所以也就不能使用基于范围的for循环。
#include<iostream>
#include<stack>
#include<queue>
using namespace std;
void test01()
{
queue<int> st;
for (int i = 0; i < 10; ++i)
st.push(i);
cout << st.size() << endl;
//for (auto& e : st)//队列没有办法通过迭代器访问
//{
// cout << e << endl;
//}
//queue<int>::iterator;//queue是容器适配器,不包含迭代器,所以不支持c11基于范围的for循环
while (!st.empty())
{
cout << st.front() << " ";//注意队列没有top只有front
st.pop();
}
cout << endl;
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
for (const auto& e : arr)//内置类型底层指针可以充当迭代器所以,所以可以使用基于范围的for循环
{
cout << e << " ";
}
cout << endl;
}
void main()
{
test01();
system("pause");
}
queue的模拟实现:stl的注意vector没有头删所以不容易适配queue,但是vector可以适配stack
template<typename T, typename con=deque<T>>
class queue
{
public:
queue() {}
~queue(){}
size_t size() const
{//return tp;
return _C.size();
}
bool empty() const
{//return tp == 0;
return _C.empty();
}
T& front()
{
return _C.front();
}
T& back()
{
return _C.back();
}
void push(const T& x)
{
_C.push_back(x);
}
void pop()
{
_C.pop_front();
}
private:
con _C;
};
}
void test01()
{
//hym::stack<int,vector<int>> st;//可以指定配接到vector容器
hym::stack<int> st;//使用默认的双端队列
for (int i = 0; i < 10; ++i)
st.push(i);
cout << st.size() << endl;
//for (auto& e : st)//栈没有办法通过迭代器访问
//{
// cout << e << endl;
//}
//stack<int>::iterator;//stack是容器适配器,不包含迭代器,所以不支持c11基于范围的for循环
while (!st.empty())
{
cout << st.top() << " ";
st.pop();
}
cout << endl;
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
for (const auto& e : arr)//内置类型底层指针可以充当迭代器所以,所以可以使用基于范围的for循环
{
cout << e << " ";
}
cout << endl;
}
void test02()
{
hym::queue<int,list<int>>q;
q.push(1);
q.push(2);
q.push(3);
q.pop();//vector没有头删,不能作为底层适配器
cout << q.front() << endl;
cout << q.back() << endl;
}
void main()
{
test02();
system("pause");
}
容器适配器:
适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该种模式是将一个类的接口转换成客户希望的另外一个接口。
#include<iostream>
#include<stack>
#include<deque>
using namespace std;
/*但是,deque有一个致命缺陷:不适合遍历,因为在遍历时,deque的迭代器要频繁的去检测其是否移动到
某段小空间的边界,导致效率低下,而序列式场景中,可能需要经常遍历,因此在实际中,需要线性结构
时,大多数情况下优先考虑vector和list,deque的应用并不多,而目前能看到的一个应用就是,STL用其作
为stack和queue的底层数据结构。*/
void test01()
{
deque<int>dq;
dq.push_back(1);
dq.push_back(2);
dq.push_back(3);
dq.push_front(10);
dq.push_front(20);
dq.push_front(30);
for (const auto& e : dq)
{
cout << e << " ";
}
cout << endl;
for (deque<int>::iterator it = dq.begin(); it != dq.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
while (!dq.empty())
{
int value = dq.front();
dq.pop_front();
cout << value << " ";
}
cout << endl;
}
void main()
{
test01();
system("pause");
}
堆操作的四个函数,标准容器适配器priority_queue自动调用make_heap、push_heap和pop_heap来维护容器的堆属性。
make_heap()
这个函数用于建堆操作, 这个函数用于建立堆。前两个参数为迭代器类型,最后一个为仿函数,用于确定建堆方式。默认使用大堆排序。可以调用官方仿函数greater<T>,构建小堆排序,也可以自定义仿函数给参数comp。
push_heap()
这个用于将堆底数据加入堆结构中。因为make_heap只能建堆,如果当前堆数据发生改变,就需要使用push_heap重回大堆/小堆。值得注意:first 到 last-1 之间的元素必须满足堆结构。它仅仅是将last之前元素插入堆中。意思就是,如果一次性插入多个元素,它只会把最后一个元素(堆底)加入堆结构中。参数与make_heap相同。
pop_heap()
用于删除堆顶元素,但不是真的删除,堆顶元素被移至last-1的位置(堆底),移走之后系统会重新将剩余的size()-1个元素组织为大根堆。即数组最大值被放在了最后。
sort_heap()
该函数就是堆排序。但前提是该结构在调用sort_heap前已经是堆结构。sort_heap内部只是把堆顶放堆底,然后再排堆,再取堆顶到新堆底,...直到排完
代码示例:
#include<iostream>
#include<queue>
#include<functional>
using namespace std;
//全局函数,排序接口
//qsort()
//make_heap()
//push_heap()
//pop_heap()
//sort_heap()
void test01()
{
vector<int> iv{ 5,8,30,2,1,4,9,7 };
priority_queue<int>pq;
for (int i = 0; i < iv.size(); ++i)
pq.push(iv[i]);
cout << pq.size() << endl;
pq.pop();
cout << pq.top() << endl;
for (const auto& e : iv)
{
cout << e << " ";
}
cout << endl;
}
void test02()
{
int arr[] = { 10 };
vector<int> iv{ 5,8,30,2,1,4,9,7 };
for (const auto& e : iv)
{
cout << e << " ";
}
cout << endl;
make_heap(iv.begin(), iv.end());//对原有结构的数据调整为大堆结构
for (const auto& e : iv)
{
cout << e << " ";
}
cout << endl;
vector<int>::iterator it = iv.end();
for (int i = 0; i < iv.size(); ++i)//堆顶的元素出堆,寻找新的堆顶,即每次把最大的值放在数组尾部,这样可以实现排序
{
pop_heap(iv.begin(), it);
it--;
}
for (const auto& e : iv)
{
cout << e << " ";
}
cout << endl;
/*push_heap(arr, arr+1);
for (const auto& e : iv)
{
cout << e << " ";
}
cout << endl;*/
}
void test04()
{
int arr[] = { 10 };
vector<int> iv{ 5,8,30,2,1,4,9,7 };
for (const auto& e : iv)
{
cout << e << " ";
}
cout << endl;
make_heap(iv.begin(), iv.end(), greater<int>());//对原有结构的数据调整为大堆结构 默认生成大根堆,为了排序完得到升序
for (const auto& e : iv)
{
cout << e << " ";
}
cout << endl;
//iv.push_back(10);
//push_heap(iv.begin(), iv.end());//进行堆的调整
//for (const auto& e : iv)
//{
// cout << e << " ";
//}
//cout << endl;
//sort_heap(iv.begin(), iv.end());
//for (const auto& e : iv)
//{
// cout << e << " ";
//}
//cout << endl;
}
//class mysort
//{
//public:
// bool operator()(int val1,int val2)
// {
// return val1 > val2;
// }
//};
void test03()
{
int arr[] = { 10 };
vector<int> iv{ 5,8,30,2,1,4,9,7 };
for (const auto& e : iv)
{
cout << e << " ";
}
cout << endl;
make_heap(iv.begin(), iv.end());//对原有结构的数据调整为大堆结构 默认生成大根堆,为了排序完得到升序
for (const auto& e : iv)
{
cout << e << " ";
}
cout << endl;
iv.push_back(10);
push_heap(iv.begin(), iv.end());//进行堆的调整
for (const auto& e : iv)
{
cout << e << " ";
}
cout << endl;
sort_heap(iv.begin(), iv.end());
for (const auto& e : iv)
{
cout << e << " ";
}
cout << endl;
}
void main()
{
test01();
system("pause");
}
仿函数的使用:重载了小括号的类或者结构体,使用对象调用这个成员函数时就叫做仿函数,仿函数分为一元仿函数和二元仿函数。返回值为bool值的仿函数叫做谓词。
仿函数例子:
#include<iostream>
using namespace std;
template <class _Ty = void>
struct my_plus {
_Ty operator()(const _Ty& _Left, const _Ty& _Right) const {
return _Left + _Right;
}
};
void main()
{
my_plus<int>pl;//对象
pl.operator()(10, 20);
pl(10, 20);//仿函数
system("pause");
}
仿函数影响排序方法的原理理解:
在使用qsort()函数进行排序时,最后一个参数实际上是一个函数指针,我们可以按照这个函数指针的返回值以及参数类型,提供不同的函数(函数名和函数实现都可以不同)从而形成不同的比较规则,这些比较规则体现在底层就是对于是否需要交换元素会有不同的判断逻辑。注意这里qsort()就可以内部就可以传入int_less或者int_greater函数名 (函数指针)来实现对应的升序或者降序排列。
理解了这一原理后,仿函数的工作机制其实完全一致,就是将仿函数对象作为参数传入到排序方法中,底层会调用这个对象所对应的仿函数(谓词)来实现比较或者判断逻辑,所以传入不同的谓词会有不同的数据组织规则。
注意下面代码其实是不合理的,因为已经将仿函数的类类型写死了,没有办法传入int_greater()这个仿函数,因为类型不匹配。具体的做法是将谓词类型当作一个模板参数,并且将这个类型的的实例化对象当作一个成员变量。这样在使用时就可以传入不同类型的谓词了。
#include<iostream>
using namespace std;
int int_less(const void* elem1, const void* elem2)
{
return (*(int*)elem1 - *(int*)elem2);
}
int int_greater(const void* elem1, const void* elem2)
{
return (*(int*)elem2 - *(int*)elem1);
}
struct int_less1
{
bool operator()(void* elem1, void* elem2)
{
return *(int*)elem1 < *(int*)elem2;
}
};
struct int_greater1
{
bool operator()(void* elem1, void* elem2)
{
return *(int*)elem1 > *(int*)elem2;
}
};
//void qsort(void* base, size_t num, size_t width, int(__cdecl* compare)(const void* elem1, const void* elem2));
void myqsort(void* base, size_t num, size_t width, int_less1 Pr = int_less1())
{
void* tmp = malloc(width);
for (int i = 0; i < num - 1; ++i)
{
for (int j = 0; j < num - i - 1; ++j)
{
if (Pr(((char*)base) + j * width, ((char*)base) + (j + 1) * width))
{
//交换
memcpy(tmp, ((char*)base) + j * width, width);
memcpy(((char*)base) + j * width, ((char*)base) + (j + 1) * width, width);
memcpy(((char*)base) + (j + 1) * width, tmp, width);
}
}
}
}
void main()
{
int ar[] = { 5,8,30,2,1,4,9,7 };
int n = sizeof(ar) / sizeof(ar[0]);
for (int i = 0; i < n; i++)
{
cout << ar[i] << " ";
}
cout << endl;
myqsort(ar,n,sizeof(int),int_less1());
//qsort(ar, n, sizeof(int), int_greater);
for (int i = 0; i < n; i++)
{
cout << ar[i] << " ";
}
system("pause");
}
priority_queue--容器适配器
#include<iostream>
#include<queue>
#include<functional>
using namespace std;
void test01()
{
vector<int> v{ 3,2,7,6,0,4,1,9,8,5 };
priority_queue<int>pq1;
for (auto& e : v)
{
pq1.push(e);
}
cout << pq1.top() << endl;
while (!pq1.empty())
{
cout << " " << pq1.top();
pq1.pop();
}
cout << endl;
priority_queue<int,vector<int>,greater<int>> pq2(v.begin(),v.end());
if (pq2.empty())
{
cout << "empty" << endl;
}
else
{
cout << "not empty" << endl;
}
cout << pq2.top() << endl;
while (!pq2.empty())
{
cout << " " << pq2.top();
pq2.pop();
}
}
void main()
{
test01();
system("pause");
}
priority_queue的使用:
#include<iostream>
#include<queue>
using namespace std;
class date
{
public:
date(int year = 1900, int month = 1, int day = 1)
: _year(year)
, _month(month)
, _day(day)
{}
bool operator<(const date& d)const
{
return (_year < d._year) ||
(_year == d._year && _month < d._month) ||
(_year == d._year && _month == d._month && _day < d._day);
}
bool operator>(const date& d)const
{
return (_year > d._year) ||
(_year == d._year && _month > d._month) ||
(_year == d._year && _month == d._month && _day > d._day);
}
friend ostream& operator<<(ostream& _cout, const date& d)
{
_cout << d._year << "-" << d._month << "-" << d._day;
return _cout;
}
private:
int _year;
int _month;
int _day;
};
void testpriorityqueue()
{
大堆,需要用户在自定义类型中提供<的重载
priority_queue<date> q1;
q1.push(date(2018, 10, 29));
q1.push(date(2018, 10, 28));
q1.push(date(2018, 10, 30));
cout << q1.top() << endl;
如果要创建小堆,需要用户提供>的重载
priority_queue<date, vector<date>, greater<date>> q2;
q2.push(date(2018, 10, 29));
q2.push(date(2018, 10, 28));
q2.push(date(2018, 10, 30));
cout << q2.top() << endl;
}
void main()
{
vector<date> v1{ date(2018, 10, 29), date(2018, 10, 28), date(2018, 10, 30) };
make_heap(v1.begin(),v1.end(),greater<date>());
system("pause");
}
priority_queue的实现1
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
namespace hym
{
template<class T, class Cont = vector<T>, class Pred = less<T>>
class priority_queue
{
public:
typedef T value_type;
typedef size_t size_type;
explicit priority_queue(const Pred& pr = Pred()) { sz = 0; }
void push(const value_type& x)
{
c.push_back(x);
push_heap(c.begin(), c.end());
sz++;
}
size_type size()
{
return sz;
}
const value_type& top() const
{
return c.front();
}
void pop()
{
pop_heap(c.begin(), c.end());
sz--;
}
void show()
{
for (const auto& e : c)
{
cout << e << " ";
}
cout << endl;
}
bool empty()
{
return sz == 0;
}
priority_queue(const value_type* first, const value_type* last,
const Pred& pr = Pred()):c(first,last)
{
make_heap(c.begin(), c.end(),pr);
sz = c.size();
}
protected:
Cont c;
Pred comp;
size_t sz;
};
}
void test01()
{
hym::priority_queue<int>pq;
pq.push(5);
pq.push(9);
pq.push(2);
pq.push(4);
pq.push(1);
pq.show();
cout << pq.size() << endl;
pq.pop();
cout << pq.top() << endl;
cout << pq.size() << endl;
}
void test02()
{
int ar[] = { 5,9,2,4,1 };
hym::priority_queue<int,vector<int>,greater<int>>pq(ar, ar + 5,greater<int>());//小堆
//hym::priority_queue<int>pq(ar, ar + 5);//大堆
pq.show();
}
void main()
{
test02();
system("pause");
}
priority_queue的实现2
#include<iostream>
#include<vector>
using namespace std;
namespace hym
{
template<class T, class Container = std::vector<T>, class Compare = less<T>>
class priority_queue
{
public:
priority_queue() {}
priority_queue(const T* first, const T* last,
const Compare& pr = Compare()) :c(first, last),comp(pr)
{
int curpos = c.size() / 2 - 1;
while (curpos >= 0)
{
_adjustdown(curpos);
curpos--;
}
}
bool empty()
{
return c.empty();
}
size_t size() const
{
return c.size();
}
const T& top()const
{
return c.front();
}
T& top()
{
return c.front();
}
void push(const T& x)
{
c.push_back(x);
adjust_up(c.size() - 1);
}
void pop()
{
std::swap(*c.begin(),*--c.end());
c.pop_back();
_adjustdown(0);
}
void show()
{
for (const auto& e : c)
{
cout << e << " ";
}
cout << endl;
}
protected:
void _adjustdown(int start)
{
int n = c.size();
int i = start;
int j = 2 * i + 1;
while (j < n)
{
//c[j]<c[j+1]
if (j + 1 < n &&comp( c[j] ,c[j + 1]))
j++;
if (comp(c[i],c[j]))
{
T tmp = c[i];
c[i] = c[j];
c[j] = tmp;
i = j;
j = 2 * i + 1;
}
else
break;
}
}
void adjust_up(int start)
{
int j = start;
int i = (j-1)/2;
while (i >= 0)
{
if (comp(c[i], c[j]))
{
T tmp = c[i];
c[i] = c[j];
c[j] = tmp;
j = i;
i = (j - 1) / 2;
}
else
break;
}
}
private:
Container c;
Compare comp;
};
}
void test01()
{
int ar[] = { 53,17,78,9,45,65,87,23 };
int n = sizeof(ar) / sizeof(ar[0]);
hym::priority_queue<int>pq(ar,ar+8);
pq.show();
}
void test02()
{
int ar[] = { 53,17,78,9,45,65,87,23 };
int n = sizeof(ar) / sizeof(ar[0]);
hym::priority_queue<int>pq(ar, ar + 8);
pq.push(50);
pq.show();
}
void test03()
{
int ar[] = { 53,17,78,9,45,65,87,23 };
int n = sizeof(ar) / sizeof(ar[0]);
hym::priority_queue<int>pq(ar, ar + 8);
pq.push(50);
pq.pop();
pq.show();
}
void test04()
{
int ar[] = { 53,17,78,9,45,65,87,23 };
int n = sizeof(ar) / sizeof(ar[0]);
//hym::priority_queue<int>pq(ar, ar + 8);
hym::priority_queue<int,vector<int>,greater<int>>pq(ar, ar + 8,greater<int>());
pq.show();
}
void main()
{
test04();
system("pause");
}