启迪思维:顺序栈

借用觉先老大说的一句话“窃以为,做一个程序员,一要钻下去,积累技术,二要跳出来,影响世界(虽然只是一点点)”作为开篇,数据结构和算法这门学科是有些枯燥和难学,需要大家在没有苍小姐的夜晚慢慢思考和实践,一直来我都希望用更幽默的方式来总结这方面的知识,这样大家阅读文章的时候也轻松点,无奈程序写的时间长了和小学语文没有毕业(经常被女朋友鄙视),文字功底更差.......分享两个最近学习的小知识

1、为什么在二进制、八进制、十进制、十六进制中只有十进制被人类广泛应用?举起双手看看一共有多少个指头,就能找到一个相对合理的解释(万物存在必有因)

2、程序中为什么用两个等号(==)表示相等呢,为什么不直接用一个等号(=)?这个是因为在程序中用赋值的概率远高于判断两个变量相等,这样设计是减少大家多写等号的机会。

 

一:概念

栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。它按照后进先出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。栈具有记忆作用,对栈的插入与删除操作中,不需要改变栈底指针。栈是允许在同一端进行插入和删除操作的特殊线性表。允许进行插入和删除操作的一端称为栈顶(top),另一端为栈底(bottom);栈底固定,而栈顶浮动;栈中元素个数为零时称为空栈。插入一般称为进栈(push),删除则称为退栈(pop)。栈也称为后进先出表

二:示例图

 顺便空栈示例图如下:

顺便非空栈示例图如下:

三:栈的应用

1、函数的返回地址和参数;

2、临时变量:包括函数的非静态局部变量以及编译器自动生成的其他临时变量;

3、二进制转换其他进制(后面有相关代码分析)

4、解析程序的中的括号匹配问题;

5、逆波兰计算器;

栈从代码的角度看,实现起来非常简单,但栈在程序的运行中有着举足轻重的作用(这个就和苍老师在我们屌丝心中一样重要),从这能看出来在平时项目开发中,写代码应该保持简单、易懂,这样才是最受欢迎的工程师。

四:代码分析

1、元素入栈:

学习小甲鱼老师的原则"no pic you say a J8",上图:

代码分析如下:

 1 /**
 2  *元素入栈
 3  */
 4 void Push(const T &e){
 5 
 6     //如果当前栈位置已经满,动态扩展栈长度为原链表2倍
 7     if(GetSize() == size){
 8         //创建一个新的指针数组
 9         T *newBase = new T[size*2];
10         //复制原空间的数据到新创建空间
11         memcpy(newBase,base,sizeof(base)+1);
12         //修改栈顶指针值
13         top = size + base;
14         //修改栈大小
15         size = size *2;
16         //这种删除内存很危险,更多请参考boost里shared_array
17         delete[] base;
18         //指向新空间
19         base = newBase;
20     }
21     //1、压入元素到栈顶;2、改变栈顶指向
22     *top++ = e;
23 }

2、元素出栈

学习小甲鱼老师的原则"no pic you say a J8",上图:

代码分析如下:

 1 /**
 2  *元素出栈
 3  */
 4 void Pop(T &e){
 5     //1、获取栈顶元素;2、改变栈顶指向
 6     //--top和top--的区别:top--在内部创建一个临时变量,
 7     //--top直接减后直接返回,可以总结--top效率稍微高
 8     e = *--top;
 9 }
10 
11 /**
12  *获取栈顶元素
13  */
14 void GetTop(T &e){
15     //如果栈不为空,取出栈顶元素
16     if(top > base){
17         e = *(--top);
18     }
19 }

3、清空链表 

1 /**
2  * 清空栈数据
3  */
4 void Clear(){
5     //直接改变栈顶指向栈顶,这个也解释为什么硬盘格式化后,高手还可以通过某种技术恢复数据
6     top = base;
7 }

4、判断是否为空

1 /**
2  *判断栈是否为空
3  */
4 bool IsEmpty(){
5     return top == base;
6 }

5、计算栈的大小 

1 /**
2  *获取栈的大小,关于指针的知识请阅读相关资料
3  */
4 int GetSize(){
5     return top - base;
6 }

 6、测试相关

测试代码如下:

 1 /**
 2  *测试栈的相关方法
 3  */
 4 void test(){
 5     std::cout<<"-----------push stack begin------------"<<std::endl;
 6     for(size_t i = 0; i < 5; ++i){
 7         Push(i);
 8     }
 9     std::cout<<"-----------push stack end------------"<<std::endl;
10 
11     std::cout<<"frist stack length="<<GetSize()<<std::endl;
12 
13     std::cout<<"-----------pop stack begin------------"<<std::endl;
14     T e;
15     for(size_t i = 0; i < 3; ++i){
16         Pop(e)    ;
17         std::cout<<"e is value = "<<e<<"\n";
18     }
19     std::cout<<"-----------pop stack end------------"<<std::endl;
20 
21     std::cout<<"secend stack size="<<GetSize()<<std::endl;
22     Clear();
23     std::cout<<"third stack size="<<GetSize()<<std::endl;
24 }

运行结果如下图:

7、完整代码 

  1 /*
  2  * ArrayStack.h
  3  *
  4  *  Created on: May 3, 2013
  5  *      Author: sunysen
  6  */
  7 
  8 #ifndef ARRAYSTACK_H_
  9 #define ARRAYSTACK_H_
 10 
 11 template <class T>
 12 class ArrayStack{
 13 private:
 14 int size;//栈的大小
 15 T *base;//栈底
 16 T *top; //栈顶
 17 public:
 18 /**
 19  *初始化一个栈,根据指定大小创建一个指针数组,栈顶等于栈低
 20  *explicit  只对构造函数起作用,用来抑制隐式转换
 21  */
 22 explicit ArrayStack(int size):size(size),base(new T[size]){
 23     top = base;
 24 }
 25 ~ArrayStack(){
 26     //这种删除内存很危险,更多请参考boost里shared_array
 27     delete[] base;
 28 }
 29 /**
 30  *获取栈的大小,关于指针的知识请阅读相关资料
 31  */
 32 int GetSize(){
 33     return top - base;
 34 }
 35 
 36 /**
 37  *判断栈是否为空
 38  */
 39 bool IsEmpty(){
 40     return top == base;
 41 }
 42 /**
 43  * 清空栈数据
 44  */
 45 void Clear(){
 46     //直接改变栈顶指向栈顶,这个也解释为什么硬盘格式化后,高手还可以通过某种技术恢复数据
 47     top = base;
 48 }
 49 
 50 /**
 51  *元素出栈
 52  */
 53 void Pop(T &e){
 54     //1、获取栈顶元素;2、改变栈顶指向
 55     //--top和top--的区别:top--在内部创建一个临时变量,
 56     //--top直接减后直接返回,可以总结--top效率稍微高
 57     e = *--top;
 58 }
 59 
 60 /**
 61  *获取栈顶元素
 62  */
 63 void GetTop(T &e){
 64     e = *top;
 65 }
 66 
 67 /**
 68  *元素入栈
 69  */
 70 void Push(const T &e){
 71 
 72     //如果当前栈位置已经满,动态扩展栈长度为原链表2倍
 73     if(GetSize() == size){
 74         //创建一个新的指针数组
 75         T *newBase = new T[size*2];
 76         //复制原空间的数据到新创建空间
 77         memcpy(newBase,base,size);
 78         //修改栈顶指针值
 79         top = size + base;
 80         //修改栈大小
 81         size = size *2;
 82         //这种删除内存很危险,更多请参考boost里shared_array
 83         delete[] base;
 84     }
 85     //1、获取栈顶元素;2、改变栈顶指向
 86     *top++ = e;
 87 }
 88 
 89 /**
 90  *测试栈的相关方法
 91  */
 92 void test(){
 93     std::cout<<"-----------push stack begin------------"<<std::endl;
 94     for(size_t i = 0; i < 5; ++i){
 95         Push(i);
 96     }
 97     std::cout<<"-----------push stack end------------"<<std::endl;
 98 
 99     std::cout<<"frist stack length="<<GetSize()<<std::endl;
100 
101     std::cout<<"-----------pop stack begin------------"<<std::endl;
102     T e;
103     for(size_t i = 0; i < 3; ++i){
104         Pop(e)    ;
105         std::cout<<"e is value = "<<e<<"\n";
106     }
107     std::cout<<"-----------pop stack end------------"<<std::endl;
108 
109     std::cout<<"secend stack size="<<GetSize()<<std::endl;
110     Clear();
111     std::cout<<"third stack size="<<GetSize()<<std::endl;
112 }
113 
114 };
115 
116 
117 #endif /* ARRAYSTACK_H_ */
View Code

五:环境

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

2、开发工具:Eclipse+make

六:题记

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

2、我自己能手动写上面代码,离不开郝斌、高一凡、侯捷、严蔚敏等老师的书籍和视频指导,在这里感谢他们;

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

 

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

 

posted @ 2013-05-15 17:26  sunysen  阅读(1268)  评论(5编辑  收藏  举报