当前位置: 首页 > news >正文

网站开发的内容和特点wordpress 批量上传产品

网站开发的内容和特点,wordpress 批量上传产品,西安建设工程网,百度站长工具平台登录stack栈正常情况下&#xff0c;应该这样实现栈template <class T> class stack { private:T* _arr;size_t _top;size_t _capacity; };主要就是在栈顶插入&#xff0c;在栈顶删除&#xff0c;那我们的栈就可以不用原生的实现&#xff0c;直接用现有的容器&#xff0c;如ve…

stack栈

正常情况下,应该这样实现栈

template <class T>
class stack
{
private:T* _arr;size_t _top;size_t _capacity;
};

主要就是在栈顶插入,在栈顶删除,那我们的栈就可以不用原生的实现,直接用现有的容器,如vector,list去封装一下,只要能在一段进行插入删除即可

比如这样,

template <class T>
class stack
{
private:vector<T> _arr;//or list<T> _arr
};

但这样就写死了,只能是数组栈/链式栈,模板参数不一定是数据类型,还可以是容器类型

因此定义一个容器Container,传入相应的容器模板,用Container适配转换出stack

template <class T,class Container>
class stack
{
private:Container _con;//vector,list等的底层容器
};

这样传不同的容器就可以是数组栈,也可以是链式栈

	sxm::stack<int, vector<int>> st;sxm::stack<int, list<int>> st2;

适配器

什么是适配器?是基于现有的容器,对其进行底层的封装,通过封装这个容器来实现需要的功能,提供了特定的接口,隐去了原本现有容器的部分功能。只暴露符合该数据结构特性的方法。

不用写构造函数了,因为_con是一个自定义类型(vector<T>/list<T>等),即使没有显示写初始化列表,也会走初始化列表,然后调用它的默认构造

模板参数传类型,函数参数传对象

namespace sxm
{ template <class T,class Container=vector<T>>//模板参数传类型,给个缺省值//template <class T, class Container = deque<T>>class stack{public:void push(const T& x){//尾部当栈顶_con.push_back(x);}void pop(){return _con.pop_back();}const T& top()const{return _con.back();//不要使用[],因为容易不一定是vector,也有可能是list,而list没有[]重载}size_t size()const{return _con.size();}bool empty()const{return _con.empty();}private:Container _con;//底层容器};
}

queuq队列

queue也是同理,但是队列是在一端进,另一端出,如果用vector容器来适配就不合适,因为vector不支持头删pop_front(),效率极低,但可以用erase+begin,只是太麻烦,可以用list容器

namespace sxm
{template <class T, class Container = list<T>>//template <class T, class Container = deque<T>>class queue//队列先进先出{public:void push(const T& x){_con.push_back(x);}void pop(){_con.pop_front();}const T& front()const//队头出{return _con.front();}const T& back()const//队尾入{return _con.back();}size_t size()const{return _con.size();}bool empty()const{return _con.empty();}private:Container _con;//底层容器};
}

deque

但是C++标准库里的默认容器是deque

deque是缝合怪

vector和list的缝合,支持vector的下标随机访问[],和list的头尾的插入删除,因此搞出了deque

deque本质上是双端队列,允许在队列的两端进行插入删除,时间复杂度为O(1)

vector

优点:

1.尾插尾删效率不错,支持高效的下标随机访问

2.物理空间连续,缓存利用率高

缺点:

1.空间不够需要扩容,扩容有代价

2.头部和中间插入的效率低

list

优点:

1.按需申请空间,不需要扩容

2.支持任意位置的插入删除

缺点:

1.不支持下标的随机访问(空间碎)

deque:

与vector的连续内存不同,deque采用分段连续内存,有一个中控数组,用来存储每个内存块的指针,第一个内存块的数组指针处于中控数组的中间部位,当进行头插时,在左侧新增内存块,避免了vector进行头插需要移动整个数组的操作。

deque迭代器的实现

迭代器有四个指针:

first指向当前buff的起始位置

last指向当前buff的末尾(最后一个元素的下一个位置)

cur代表访问这个buff的当前数据

node是指向中控器中某个元素(当前内存块buff)的指针,是一个二级指针

deque插入的实现

尾插找到finish,如果finish迭代器里的cur!=last,表示没有满,直接在cur的位置插入即可,如果已经满了,说明最后一个buff已经满了,接下来增加新的buff,这时在node的下一个位置给给这个新的buff的地址,更新迭代器中的指针,再进行插入,cur指向当前有效元素的下一个位置。

如果是头插,找到当前node的前一个位置,开一段新的buff,更新迭代器中的四个指针,这个cur指向元素本身,不是元素的下一个位置,因为start相当于begin。指向第一个数据,只要cur!=first,那cur就一直往前走,直到这个buff满了

那如果是中间插入呢,insert与erase,效率贼低,需要移动buff中的数据,两种选择,当前buff挪动还是所有buff挪动。如果是所有buff挪动,那下一个buff的数据会进入到这个buff里,类似于vectorO(n);而如果只控制当前buff,可对当前buff扩容,但是会导致每个buff的大小不一样。导致[]的效率进一步下降,不能直接通过/ 来判断是在第几个buff,而需要减去之前所有buff中的元素个数。库里面选择牺牲insert/erase,这里使用 / ,保证每个buff的大小不变

deque下标随机访问[]的实现

[]是如何实现的,先看是不是在第一个buff内,如果不是先把第一个buff减掉,再进行/和%

看看库里面是如何实现的--通过cur-first+n,要访问当前buff的第几个数据,相当于把当前的buff补满。相当于把起始位置挪到了开始。

如果不在当前的buff,就找到对应的buff,通过/buff_size,找到是第几个buff;然后算在这个buff的第几个位置,减去前面每个buff的数据个数,类似于%,只不过第一个buff的数据个数不确定。

总结:

1.deque头插尾插效率很高,优于list与vector(缓存利用率高)

2.下标随机访问效率也不错,但比不上vector(deque里面有好多运算)

3.中间插入效率很低(挪动插入之后的所有数据)

如果不考虑第3点,deque还是很合适的

        栈和队列一个在一端进行插入删除,一个在两端进行插入或删除,不涉及中间的插入和删除,deque可以做底层的适配器。现在栈和队列可以用同一个结构来实现了。

stack

#include<deque>
namespace sxm
{ template <class T, class Container = deque<T>>//缺省容器类型class stack{public:void push(const T& x){_con.push_back(x);}void pop(){return _con.pop_back();}const T& top()const{return _con.back();}size_t size()const{return _con.size();}bool empty()const{return _con.empty();}private:Container _con;//底层容器};
}

queue

#include<deque>
namespace sxm
{template <class T, class Container = deque<T>>class queue{public:void push(const T& x){_con.push_back(x);}void pop(){_con.pop_front();}const T& front()const{return _con.front();}const T& back()const{return _con.back();}size_t size()const{return _con.size();}bool empty()const{return _con.empty();}private:Container _con;//底层容器};
}

priority_queue优先级队列

要取优先级高的,默认是大的值优先级高,底层是堆,堆的底层是数组,默认适配容器是vector

默认是大堆

namespace sxm
{template<class T,class Container=vector<T>>class priority_queue{public://插入void AdjustUp(int child){int parent = (child - 1) / 2;while(child>0){if (_con[child] > _con[parent])//大堆{swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}void push(const T& x){//在尾部插入,向上调整(是堆),//插入之前就已经是一个堆 _con.push_back(x);//第一个数插入是堆,第二个插入向上调整也是堆,类推AdjustUp(_con.size() - 1);}//删除,先进行向下调整,要求左右子树为大堆void AdjustDown(int parent){size_t child = 2 * parent + 1;while (child<_con.size()){if (child+1<_con.size()&&_con[child] < _con[child + 1]){++child;//左右孩子中大的那个}if (_con[parent] < _con[child]){swap(_con[parent], _con[child]);parent = child;child = 2 * parent + 1;}else{break;}}}//第一个和最后一个交换,删除最后一个元素,再进行向下调整(左右子树是堆)void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();AdjustDown(0);//进行向下调整}//取堆顶元素const T& top(){return _con[0];}//堆的大小size_t size(){return _con.size();}//判空bool empty(){return _con.size() == 0;}private:Container _con;//vector类型的对象,支持下标访问};
}

优先级队列这里是写死的,这里现在是大堆,如果现在想改成小堆,难道要直接改代码或再实现一个小堆吗?

仿函数

这里引入仿函数,仿函数是一个类,重载了operator(),用于进行两个数据间的比较大小,仿函数没有成员变量,是一个空类,大小是1,它的对象可以像函数一样使用

看下面一段代码,Less<T>和Greater<T>就是两个仿函数类型,

template <class T>
class Less
{
public:bool operator()(const T& x,const T& y){return x < y;}
};template <class T>
class Greater
{
public:bool operator()(const T& x, const T& y){return x > y;}
};int main()
{Less<int> LessFunc;cout << LessFunc(1, 2);//我会认为LessFunc是一个函数名,但现在它只是一个对象return 0;
}

LessFunc(1,2),本质上是调用LessFunc()(1,2),仿函数的对象可以向函数一样调用,对象名(参数)

再比如我们看冒泡排序,

void BubbleSort(int* a, int n)
{for (int j = 0; j < n; j++){int flag = 0;for (int i = 1; i < n - j; i++){if(a[i-1] > a[i])//升序{swap(a[i - 1], a[i]);flag = 1;}}if (flag == 0){break;}}
}

这里采用的是>升序,如果要实现降序,需要调整内部代码,将">"改成"<" 。但也可以不这么做,

因为仿函数是一个类型,这时我们再加一个模板Compare,模板类型是一个仿函数类

template<class Compare>
void BubbleSort(int* a, int n,Compare com)
{for (int j = 0; j < n; j++){int flag = 0;for (int i = 1; i < n - j; i++){if (com(a[i - 1] , a[i]))//升序{swap(a[i - 1], a[i]);flag = 1;}}if (flag == 0){break;}}
}
int main()
{Less<int> LessFunc;Greater<int> GreaterFunc;int a[] = { 3,6,3,2,8 };BubbleSort(a, 5, LessFunc);
//也可以传匿名的仿函数类型的对象 如:
//BubbleSort(a,5,Less<int>());BubbleSort(a, 5, GreaterFunc);return 0;
}

        com是一个仿函数类类型的对象,它的类型可以是Less<T>仿函数类型,也可以是Greater<T>仿函数类型,这个对象通过类似于函数调用的方式com(a[i-1],a[i]),来返回真或假,进而来判断是升序还是降序。

        在主函数里面,可以定义不同类型的仿函数对象,LessFunc,GreaterFunc,通把这个仿函数对象传给冒泡排序当作参数,编译器自动推导这个仿函数对象对应的类型是Less<T>,或是GreaterFunc<T>,然后通过不同的仿函数类型的对象调用其对应的仿函数模板下的()重载,来实现想要的功能

因此,无需修改 BubbleSort 内部代码,仅通过更换传入的仿函数对象,即可切换排序方式。

//我们传一个缺省值,默认时是大堆,但如果想实现小堆,可以传一个Greater

#pragma oncetemplate <class T>
class Less
{
public:bool operator()(const T& x, const T& y){return x < y;}
};template <class T>
class Greater
{
public:bool operator()(const T& x, const T& y){return x > y;}
};namespace sxm
{template<class T,class Container=vector<T>,class Compare = Less<T>>//Compare为仿函数类型,类模板class priority_queue{public://插入void AdjustUp(int child){Compare com;//仿函数类型的对象,默认是Less仿函数类型的对象,Less对象调用类内重载的(),来比较大小int parent = (child - 1) / 2;while(child>0){if (com(_con[parent], _con[child]))//大堆,这里不写死是< 还是>,而是调用仿函数对象(默认为Less<T>类型)com,如果_con[parent]<_con[child],则交换{swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}void push(const T& x){//在尾部插入,向上调整(是堆),//插入之前就已经是一个堆 _con.push_back(x);//第一个数插入是堆,第二个插入向上调整也是堆,类推AdjustUp(_con.size() - 1);}//删除,先进行向下调整,要求左右子树为大堆void AdjustDown(int parent){Compare com;size_t child = 2 * parent + 1;while (child<_con.size()){if (child + 1 < _con.size() && com(_con[child] , _con[child + 1]))//右节点大于左节点{++child;//更新为右节点}if (com(_con[parent],_con[child]))//_con[parent]<_con[child],则交换{swap(_con[parent], _con[child]);parent = child;child = 2 * parent + 1;}else{break;}}}//第一个和最后一个交换,删除最后一个元素,再进行向下调整(左右子树是堆)void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();AdjustDown(0);//进行向下调整}//取堆顶元素const T& top(){return _con[0];}//堆的大小size_t size(){return _con.size();}//判空bool empty(){return _con.size() == 0;}private:Container _con;//vector类型的对象,支持下标访问};
}

缺省值还是很有用的,当不显示写Less时是默认调整为大堆;如果想改为小堆,则显示写一个Greater。

http://www.dtcms.com/a/514576.html

相关文章:

  • 新媒体seo培训乐清seo
  • 中山网站优化wordpress菜单链接
  • 设计外贸商城网站建设玩具租赁系统网站开发与实现
  • 网站开发团队人员构成为爱直播视频
  • 苏州工业园区网站建设通官网首页
  • 简述网站建设与维护公司注册核名流程
  • 中国建设银行网站维护阿里云网站备案
  • 有网站代码怎么建站wordpress 怎么通过数据库该域名
  • 革吉网站建设在哪下载.net网站作品
  • 新人做网络咨询的网站移动端网站开发与网页开发区别
  • 网站建设路由器怎么设置wordpress商品展示模块
  • 手机网站封装用户体验wordpress卡密系统
  • 教育行业网站建设中山排名推广
  • 网站从建设到上线流程seo优化教程培训
  • 万全网站建设下载爱南宁app下载
  • 深圳网站制作专业公司怎么在百度免费推广
  • 威海建设集团的网站是什么图片展示类的wordpress主题
  • 关于配色的网站wordpress怎么qq登录地址
  • 鄂尔多斯市东胜区城市建设局网站上海网站seo外包
  • 新手建站织梦网站添加视频教程
  • drupal网站建设数据库不改域名和空间 只改网站类型
  • 网站开发工作难吗秀网站
  • 如何让新网站快速收录机械公司网站源码
  • 网站与公众号的区别wordpress大前端美化版
  • 衡水seo_衡水网站建设-燕丰收郑州发布
  • 专门做985招聘信息的网站将网站打造成
  • 东源县住房和城乡建设部网站dedecms游戏门户网站源码
  • 佛山做外贸网站方案网站开发课程报告心得
  • 网站建设电销话术开场白新闻类的网站如何做优化
  • 网站后台添加图片链接网站怎么做维护