• 启迪思维:顺序栈


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

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

     

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

     

    一根球杆,几行代码,品世间酸甜苦辣

    如果你喜欢这篇文章,欢迎推荐

    年轻人有理想、有野心,更需要脚踏实地做事情

  • 相关阅读:
    iphone 使用委托(delegate)在不同的窗口之间传递数据
    创建单键模式的类
    读入Plist文件中的信息
    C#读取Excel,取值为空的解决办法!
    ORACLE 常见的数据类型
    ArcGISServer 将内网地图服务映射修改外网可以访问的地图服务
    C#中获取当前路径的几种方法
    sql server2005登录出错问题(转载)
    (转载)服务器控件的生命周期
    ORACLE 中ROWNUM用法总结(转载)
  • 原文地址:https://www.cnblogs.com/sunysen/p/3079756.html
Copyright © 2020-2023  润新知