启迪思维:链式队列

最近校长火了,微博上各种讽刺校长这个职位信息,还有各种公知转发这些微博(他们无非想说明自己有多么正直,鬼知道背后都干啥)更有可耻人借此炒作。其实根据各种新闻来看,猥琐少女人有企业高管、校长等等人,我们只能谴责这些心理变态的人(让哪些为恶的人下地狱),不能因此讽刺校长这个职位,这个就和有些无良媒体报道有搞IT加班累死(个人观点IT公司里累死的兄弟,应该是不懂调整心态),就判断搞IT是高危行业一样,事实上高危行业应该是挖煤、黑砖厂等等。上周参加一个公益性质的活动,就认识一个很了不起的校长(收养100的个孤儿),我自己小学校长也是非常好的人,可悲的是初中校长因贪污被双规。 

 

最近网上一贴郭美美的余额短信有闪现我等屌丝的太极眼,其实这个新闻很早都有,是新华社发出,最近因为营销的需要又被炒作起来,腾讯客户端及搜狐客户端都放在头版头条,稍微有点知识的人都知道这是个假新闻,这篇新闻后面全是推销施华洛世奇女鞋的。普通网民只重视情绪,从不管事实,这样就被营销者利用了很成功。这个仅仅是为营销,还更多是坑爹甚至坑爷的新闻,坑着那些不懂得过滤这些垃圾信息的人。

 

在网络每天都有类似这样假新闻、骗人的广告、公知的装逼(还有电视里各种广告,每次家里亲戚都问是不是真),学习过滤垃圾信息非常重要(多问、多看、多思考),坚持一到两年,就能有很好过滤信息能力(个人觉得过滤垃圾信息是搞IT人一个基本能力)平时也多和家里的亲戚说说,避免他们上当受骗。瞎扯的有点多了,下面进入正题

 

上一篇博客分析栈的相关知识和分析用数组的方式实现队列(循环顺序队列),循环顺序队列在内存中的存储位置是连续的,且编译器要求我们在编译期就要确定队列的大小,这样对于多数应用都不能很好的确定初始值(设置过大导致浪费内存,设置过小导致频繁分配造成大量内存碎片),使用了链表来实现队列,链表中的元素存储在不连续的地址,由于是动态申请内存(也会造成内存碎片),由于每个节点占用的内存空间一样并且很小,可以用内存池(boostpool)避免频繁向系统申请和释放内存,基于上面的原因很多开源项目对栈的实现都是链式队列。

 

一、示例图

 链表队列例图

二:代码分析

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、获取队列入口和出口元素:

可以看到在队列类中,GetFrontGetBack函数是发生重载了,而且是合法的。而且在调用时,只用队列类的const对象才能调用const版本的GetFrontGetBack函数,理论而非const对象可以调用任意一种,通常非const对象调用非const版本的GetFrontGetBack函数。 

具体原因:按照函数重载的定义,函数名相同而形参表有本质不同的函数称为重载。在队列类中,由于隐含的this形参的存在,const版本的函数GetFrontGetBack使得作为形参的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函数重载示例图:

 测试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 }
View Code

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_ */
View Code

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_ */
View Code

三:环境

1、运行环境:Ubuntu 10.04 LTS+VMware8.0.4+gcc4.4.3

2、开发工具:Eclipse+make

四:题记

1、上面的代码难免有bug,如果你发现代码写的有问题,请你帮忙指出,让我们一起进步,让代码变的更漂亮和更健壮;

2、鼓励自己能坚持把更多数据结构方面的知识写出来,让自己掌握更深刻,也顺便冒充下"小牛"

3、感谢Vamei老大的指导,把博客弄漂亮,不被女朋友鄙视了。

4、后续数据结构方面的代码命名规则会严格按照STL的标准,期待这样能有缘人看更明白

 

欢迎继续阅读“启迪思维:数据结构和算法”系列

posted @ 2013-06-07 17:11  sunysen  阅读(1256)  评论(2编辑  收藏  举报