启迪思维:链式队列
最近校长火了,微博上各种讽刺校长这个职位信息,还有各种公知转发这些微博(他们无非想说明自己有多么正直,鬼知道背后都干啥),更有可耻人借此炒作。其实根据各种新闻来看,猥琐少女人有企业高管、校长等等人,我们只能谴责这些心理变态的人(让哪些为恶的人下地狱),不能因此讽刺校长这个职位,这个就和有些无良媒体报道有搞IT加班累死(个人观点IT公司里累死的兄弟,应该是不懂调整心态),就判断搞IT是高危行业一样,事实上高危行业应该是挖煤、黑砖厂等等。上周参加一个公益性质的活动,就认识一个很了不起的校长(收养100的个孤儿),我自己小学校长也是非常好的人,可悲的是初中校长因贪污被双规。
最近网上一贴郭美美的余额短信有闪现我等屌丝的太极眼,其实这个新闻很早都有,是新华社发出,最近因为营销的需要又被炒作起来,腾讯客户端及搜狐客户端都放在头版头条,稍微有点知识的人都知道这是个假新闻,这篇新闻后面全是推销施华洛世奇女鞋的。普通网民只重视情绪,从不管事实,这样就被营销者利用了很成功。这个仅仅是为营销,还更多是坑爹甚至坑爷的新闻,坑着那些不懂得过滤这些垃圾信息的人。
在网络每天都有类似这样假新闻、骗人的广告、公知的装逼(还有电视里各种广告,每次家里亲戚都问是不是真),学习过滤垃圾信息非常重要(多问、多看、多思考),坚持一到两年,就能有很好过滤信息能力(个人觉得过滤垃圾信息是搞IT人一个基本能力),平时也多和家里的亲戚说说,避免他们上当受骗。瞎扯的有点多了,下面进入正题
上一篇博客分析栈的相关知识和分析用数组的方式实现队列(循环顺序队列),循环顺序队列在内存中的存储位置是连续的,且编译器要求我们在编译期就要确定队列的大小,这样对于多数应用都不能很好的确定初始值(设置过大导致浪费内存,设置过小导致频繁分配造成大量内存碎片),使用了链表来实现队列,链表中的元素存储在不连续的地址,由于是动态申请内存(也会造成内存碎片),由于每个节点占用的内存空间一样并且很小,可以用内存池(boost的pool)避免频繁向系统申请和释放内存,基于上面的原因很多开源项目对栈的实现都是链式队列。
一、示例图
二:代码分析
1、节点入队
过程如示例图:
代码分析:
1 /** 2 * 节点入队列 3 */ 4 void EnQueue(const value_type& value){ 5 //创建一个新节点 6 LNode<T> *p = new LNode<T>(value); 7 8 //判断队列是否为空,如果为空直接赋值给front,back 9 if(IsEmpty()){ 10 back = front = p; 11 }else{ 12 //不为空:入口指针指向新的节点 13 back->next = p; 14 //改变入口指针为新创建的节点 15 back = p; 16 } 17 18 }
2、节点出队
过程如示例图:
代码分析:
1 void DeQueue(){ 2 //如果队列不为空,则出队列 3 if(!IsEmpty()){ 4 //释放删除节点占用内存,更多关于auto_ptr知识,请阅读memory里auto_ptr源码 5 std::auto_ptr<LNode<T> > new_prt(front); 6 //修改队列出口指针指向下一个节点 7 front = front->next; 8 } 9 }
3、获取队列入口和出口元素:
可以看到在队列类中,GetFront和GetBack函数是发生重载了,而且是合法的。而且在调用时,只用队列类的const对象才能调用const版本的GetFront和GetBack函数,理论而非const对象可以调用任意一种,通常非const对象调用非const版本的GetFront和GetBack函数。
具体原因:按照函数重载的定义,函数名相同而形参表有本质不同的函数称为重载。在队列类中,由于隐含的this形参的存在,const版本的函数GetFront和GetBack使得作为形参的this指针的类型变为指向const对象的指针,而非const版本的使得作为形参的this指针就是正常版本的指针。此处是发生重载的本质。重载函数在最佳匹配过程中,对于const对象调用的就选取const版本的成员函数,而普通的对象调用就选取非const版本的成员函数,具体的测试请参考test1和test2函数,代码如下。
1 /** 2 *获取队列出口元素 3 */ 4 reference GetFront(){ 5 std::cout<<"GetFront reference"<<std::endl; 6 return front->data; 7 } 8 /** 9 *获取队列出口元素 10 */ 11 const_reference GetFront() const{ 12 std::cout<<"GetFront const_reference"<<std::endl; 13 return front->data; 14 } 15 /** 16 *获取队列入口元素 17 */ 18 reference GetBack(){ 19 std::cout<<"GetBack reference"<<std::endl; 20 return back->data; 21 } 22 /** 23 *获取队列入口元素 24 */ 25 const_reference GetBack() const{ 26 std::cout<<"GetBack const_reference"<<std::endl; 27 return back->data; 28 }
4、清空队列
1 /** 2 *清空队列并回收资源 3 */ 4 void Clear(){ 5 //循环判断队列是否为空 6 while(!IsEmpty()){ 7 //节点出对并回收资源 8 this->DeQueue(); 9 } 10 }
5、判断队列是否为空
1 /** 2 * 判断队列是否为空 3 */ 4 bool IsEmpty() const{ 5 return front == 0; 6 }
6、计算队列长度
1 /** 2 *计算机队列大小 3 */ 4 size_t GetSize() const{ 5 6 size_t size = 0; 7 //获取队列出口 8 LNode<T> *p = front; 9 //循环整这个栈大小,当栈==0,表示栈已经遍历完成 10 while(p != 0){ 11 ++size; 12 //指向下一个栈节点 13 p = p->next; 14 } 15 16 return size; 17 }
7、运行结果
测试队列各方法示例图:
测试const函数重载示例图:
测试代码如下:
1 /** 2 * 测试队列各种方法 3 */ 4 void test(){ 5 T e; 6 std::cout<<"-----------EnQueue queue begin------------"<<std::endl; 7 for(size_t i = 1; i < 5; ++i){ 8 EnQueue(i); 9 e = GetBack(); 10 std::cout<<"e is value = "<<e<<"\n"; 11 } 12 std::cout<<"-----------EnQueue queue end------------"<<std::endl; 13 14 std::cout<<"frist queue length="<<GetSize()<<std::endl; 15 16 std::cout<<"-----------DeQueue queue begin------------"<<std::endl; 17 18 for(size_t i = 1; i < 3; ++i){ 19 e = GetFront(); 20 DeQueue(); 21 std::cout<<"e is value = "<<e<<"\n"; 22 } 23 std::cout<<"-----------DeQueue queue end------------"<<std::endl; 24 25 std::cout<<"-----------GetFront queue begin------------"<<std::endl; 26 27 T ee = GetFront(); 28 29 std::cout<<"ee is value = "<<ee<<"\n"; 30 31 std::cout<<"-----------GetFront queue end------------"<<std::endl; 32 33 std::cout<<"secend queue size="<<GetSize()<<std::endl; 34 Clear(); 35 std::cout<<"third queue size="<<GetSize()<<std::endl; 36 } 37 38 /** 39 *测试const函数重载 40 */ 41 void test1() { 42 T e; 43 std::cout<<"-----------method non const GetBack queue begin------------"<<std::endl; 44 for(size_t i = 1; i < 2; ++i){ 45 EnQueue(i); 46 e = GetBack(); 47 std::cout<<"e is value = "<<e<<"\n"; 48 } 49 std::cout<<"-----------method non const GetBack queue end------------"<<std::endl; 50 51 std::cout<<"-----------method non const GetBack const queue begin------------"<<std::endl; 52 T const ee = GetBack(); 53 std::cout<<"e is value = "<<ee<<"\n"; 54 std::cout<<"-----------method non const GetBack const queue end------------"<<std::endl; 55 } 56 57 /** 58 *测试const函数重载 59 */ 60 void test2() const { 61 T e; 62 std::cout<<"-----------method const GetBack queue begin------------"<<std::endl; 63 for(size_t i = 1; i < 2; ++i){ 64 e = GetBack(); 65 std::cout<<"e is value = "<<e<<"\n"; 66 } 67 std::cout<<"-----------method const GetBack queue end------------"<<std::endl; 68 69 std::cout<<"-----------method const GetBack const queue begin------------"<<std::endl; 70 T const ee = GetBack(); 71 std::cout<<"e is value = "<<ee<<"\n"; 72 std::cout<<"-----------method const GetBack const queue end------------"<<std::endl; 73 }
8、完整代码
LinkQueue.h 如下:
1 /* 2 * ListQuene.h 3 * 4 * Created on: May 16, 2013 5 * Author: sunysen 6 */ 7 8 #ifndef LISTQUENE_H_ 9 #define LISTQUENE_H_ 10 #include "core/node/LNode.h" 11 /** 12 *基于链表实现的队列 13 */ 14 template <class T> 15 class LinkQueue{ 16 private: 17 LNode<T> *front;//出队口指针 18 LNode<T> *back;//入队口指针 19 20 typedef T& reference;//引入STL里边萃取概率,在目前的别名仅有的作用便于理解 21 typedef const T& const_reference;//引入STL里边萃取概率,在目前的别名仅有的作用便于理解 22 typedef T value_type;//引入STL里边萃取概率,在目前的别名仅有的作用便于理解 23 public: 24 /** 25 * 构造函数,初始化入队和出队指针 26 */ 27 LinkQueue():front(0),back(0){ 28 } 29 30 /** 31 *析构函数,离开作用域回收资源 32 */ 33 ~LinkQueue(){ 34 Clear(); 35 } 36 37 /** 38 *清空队列并回收资源 39 */ 40 void Clear(){ 41 //循环判断队列是否为空 42 while(!IsEmpty()){ 43 //节点出对并回收资源 44 this->DeQueue(); 45 } 46 } 47 /** 48 *获取队列出口元素 49 */ 50 reference GetFront(){ 51 std::cout<<"GetFront reference"<<std::endl; 52 return front->data; 53 } 54 /** 55 *获取队列出口元素 56 */ 57 const_reference GetFront() const{ 58 std::cout<<"GetFront const_reference"<<std::endl; 59 return front->data; 60 } 61 /** 62 *获取队列入口元素 63 */ 64 reference GetBack(){ 65 std::cout<<"GetBack reference"<<std::endl; 66 return back->data; 67 } 68 /** 69 *获取队列入口元素 70 */ 71 const_reference GetBack() const{ 72 std::cout<<"GetBack const_reference"<<std::endl; 73 return back->data; 74 } 75 76 /** 77 * 节点入队列 78 */ 79 void EnQueue(const value_type& value){ 80 //创建一个新节点 81 LNode<T> *p = new LNode<T>(value); 82 83 //判断队列是否为空,如果为空直接赋值给front,back 84 if(IsEmpty()){ 85 back = front = p; 86 }else{ 87 //不为空:入口指针指向新的节点 88 back->next = p; 89 //改变入口指针为新创建的节点 90 back = p; 91 } 92 93 } 94 95 void DeQueue(){ 96 //如果队列不为空,则出队列 97 if(!IsEmpty()){ 98 //释放删除节点占用内存,更多关于auto_ptr知识,请阅读memory里auto_ptr源码 99 std::auto_ptr<LNode<T> > new_prt(front); 100 //修改队列出口指针指向下一个节点 101 front = front->next; 102 } 103 } 104 /** 105 * 判断队列是否为空 106 */ 107 bool IsEmpty() const{ 108 return front == 0; 109 } 110 /** 111 *计算机队列大小 112 */ 113 size_t GetSize() const{ 114 115 size_t size = 0; 116 //获取队列出口 117 LNode<T> *p = front; 118 //循环整这个栈大小,当栈==0,表示栈已经遍历完成 119 while(p != 0){ 120 ++size; 121 //指向下一个栈节点 122 p = p->next; 123 } 124 125 return size; 126 } 127 /** 128 * 测试队列各种方法 129 */ 130 void test(){ 131 T e; 132 std::cout<<"-----------EnQueue queue begin------------"<<std::endl; 133 for(size_t i = 1; i < 5; ++i){ 134 EnQueue(i); 135 e = GetBack(); 136 std::cout<<"e is value = "<<e<<"\n"; 137 } 138 std::cout<<"-----------EnQueue queue end------------"<<std::endl; 139 140 std::cout<<"frist queue length="<<GetSize()<<std::endl; 141 142 std::cout<<"-----------DeQueue queue begin------------"<<std::endl; 143 144 for(size_t i = 1; i < 3; ++i){ 145 e = GetFront(); 146 DeQueue(); 147 std::cout<<"e is value = "<<e<<"\n"; 148 } 149 std::cout<<"-----------DeQueue queue end------------"<<std::endl; 150 151 std::cout<<"-----------GetFront queue begin------------"<<std::endl; 152 153 T ee = GetFront(); 154 155 std::cout<<"ee is value = "<<ee<<"\n"; 156 157 std::cout<<"-----------GetFront queue end------------"<<std::endl; 158 159 std::cout<<"secend queue size="<<GetSize()<<std::endl; 160 Clear(); 161 std::cout<<"third queue size="<<GetSize()<<std::endl; 162 } 163 164 /** 165 *测试const函数重载 166 */ 167 void test1() { 168 T e; 169 std::cout<<"-----------method non const GetBack queue begin------------"<<std::endl; 170 for(size_t i = 1; i < 2; ++i){ 171 EnQueue(i); 172 e = GetBack(); 173 std::cout<<"e is value = "<<e<<"\n"; 174 } 175 std::cout<<"-----------method non const GetBack queue end------------"<<std::endl; 176 177 std::cout<<"-----------method non const GetBack const queue begin------------"<<std::endl; 178 T const ee = GetBack(); 179 std::cout<<"e is value = "<<ee<<"\n"; 180 std::cout<<"-----------method non const GetBack const queue end------------"<<std::endl; 181 } 182 183 /** 184 *测试const函数重载 185 */ 186 void test2() const { 187 T e; 188 std::cout<<"-----------method const GetBack queue begin------------"<<std::endl; 189 for(size_t i = 1; i < 2; ++i){ 190 e = GetBack(); 191 std::cout<<"e is value = "<<e<<"\n"; 192 } 193 std::cout<<"-----------method const GetBack queue end------------"<<std::endl; 194 195 std::cout<<"-----------method const GetBack const queue begin------------"<<std::endl; 196 T const ee = GetBack(); 197 std::cout<<"e is value = "<<ee<<"\n"; 198 std::cout<<"-----------method const GetBack const queue end------------"<<std::endl; 199 } 200 }; 201 202 203 204 #endif /* LISTQUENE_H_ */
Common.h
1 /* 2 * Common.h 3 * 4 * Created on: May 17, 2012 5 * Author: sunysen 6 */ 7 8 #ifndef COMMON_H_ 9 #define COMMON_H_ 10 11 #include <iostream> 12 #include "memory" 13 #include "string" 14 #include "string.h" 15 #include <math.h> 16 17 18 using namespace std; 19 #endif /* COMMON_H_ */
三:环境
1、运行环境:Ubuntu 10.04 LTS+VMware8.0.4+gcc4.4.3;
2、开发工具:Eclipse+make
四:题记
1、上面的代码难免有bug,如果你发现代码写的有问题,请你帮忙指出,让我们一起进步,让代码变的更漂亮和更健壮;
2、鼓励自己能坚持把更多数据结构方面的知识写出来,让自己掌握更深刻,也顺便冒充下"小牛";
3、感谢Vamei老大的指导,把博客弄漂亮,不被女朋友鄙视了。
4、后续数据结构方面的代码命名规则会严格按照STL的标准,期待这样能有缘人看更明白
欢迎继续阅读“启迪思维:数据结构和算法”系列