zoukankan      html  css  js  c++  java
  • 纪念逝去的岁月——C++实现一个栈(使用类模板)

    这个版本是上个版本的加强版,上个版本的代码:http://www.cnblogs.com/fengbohello/p/4542912.html


     目录

    1、代码

    2、运行结果


     1、代码

    1.1 调试信息的配置

    //一个调试开关,如果要看调试信息,就把这个开关的注释去掉
    //#define USEDEBUG
    
    //如果调试开关打开了,就定义好调试的输出函数(其实是个宏),
    #ifdef USEDEBUG
    #define DEBUG(fmt, arg...)
        do{
            printf("%s %d %s() : ", __FILE__, __LINE__, __func__);
            printf(fmt, ##arg);
        }while(0)
    #else
    //如果没有打开,这个函数什么也不做
    #define DEBUG(fmt, arg...)
    #endif

    1.2 栈类的声明

    //定义模版类 ClsStack
    template<typename T> class ClsStack
    {
        //这个类的=型私有数据,主要用于对栈的内存分配进行管理,
        //用户不需要关心内存,只需要调用对外提供的几个方法就可以了
        private :
            T ** __m_Data;//存储数据的内存开始地址
            int  __m_pos;//记录栈尾的位置,插入数据时插入这个位置
            int  __m_memsize;//记录内存的总数
    
        protected :
            //重新分配内存空间,可以减小,也可以增大
            int __resize(int n);
    
            //获取给定参数的双倍内存,其实主要目的是防止参数是0
            int __doublesize(int n);
    
        public :
            ClsStack(int n = 0);
            ~ClsStack();
    
            //弹出栈顶
            int  pop (T ** ppData);
    
            //获取栈顶元素,但是不弹出
            int  top (T ** ppData);
    
            //向栈添加数据
            int  push(T * pData);
    
            //清空整个栈的数据
            int clear(void (*)(T*));
    
            //输出整个栈的数据,用于调试
            void printStack(T * p[], int pos);
    };

    1.3 构造函数的实现

    //构造函数
    //默认参数值是0
    //参数非零时的作用是用于初始化栈空间的大小
    template<typename T> ClsStack<T>::ClsStack(int n)
    {
        __m_Data = NULL;
        __m_pos = -1;
        __m_memsize = 0;
    
        if(0 != n)
        {
            __m_Data = new T * [n];
            if(NULL != __m_Data)
            {
                __m_memsize = n;
            }
        }
    }

    1.4) 析构函数的实现

    //析构函数
    //在栈对象被销毁时,需要把申请的内存空间释放
    template<typename T> ClsStack<T>::~ClsStack()
    {
        if(NULL != __m_Data)
        {
            delete __m_Data;
            __m_Data = NULL;
        }
        __m_pos = -1;
        __m_memsize = 0;
    }

    1.5)内存控制函数

    //计算新的内存空间
    //当参数是0的时候,指定内存空间是1
    //参数不是0的时候,内存加倍
    template<typename T> int ClsStack<T>::__doublesize(int n)
    {
        int x = 0;
        if(0 == n)
        {
            x = 1;
        }
        else
        {
            x = n * 2;
        }
    
        return x;
    }
    
    //重新设定栈的大小
    //就是扩展当前的内存容量到指定的大小
    template<typename T> int ClsStack<T>::__resize(int n)
    {
        T ** p = new T * [n];
        if(NULL == p)
        {
            return -1;
        }
        memset(p, 0, sizeof(T *) * (n));
        if(NULL != __m_Data)
        {
            //printStack(__m_Data, __m_pos);
            if( NULL == memcpy(p, __m_Data, __m_memsize * sizeof(T *)))
            {
                DEBUG("memcpy faild
    ");
                delete p;
                return -1;
            }
            //printStack(p, __m_pos);
            delete __m_Data;
        }
        __m_Data = p;
        __m_memsize = n;
    
        return 0;
    }

    1.6)栈操作函数的实现

    //弹出数据
    //数据通过参数指定的指针返回
    template<typename T> int ClsStack<T>::pop(T ** ppData)
    {
        if(NULL == ppData)
        {
            return -1;
        }
        int r = 0;
        if(-1 == __m_pos)
        {
            *ppData = NULL;
            r = -1;
        }
        else
        {
            *ppData = __m_Data[__m_pos --];
            r = 0;
            DEBUG("memsize : [%u], pos : [%d], p = [0X%08X]
    ", __m_memsize, __m_pos + 1, (unsigned int)*ppData);
        }
    
        return r;
    }
    
    //获取栈顶元素,并不弹出
    template<typename T> int ClsStack<T>::top(T ** ppData)
    {
        if(NULL == ppData)
        {
            return -1;
        }
        int r = 0;
        if(-1 == __m_pos)
        {
            *ppData = NULL;
            r = -1;
        }
        else
        {
            *ppData = __m_Data[__m_pos];
            r = 0;
        }
    
        return r;
    }
    
    //向栈压入元素
    //栈会自己判断内存,如果内存不足会自动增加内存
    template<typename T> int ClsStack<T>::push(T * pData)
    {
        if(__m_pos + 1 >= __m_memsize)
        {
            int n = __doublesize(__m_memsize);
            if(0 != __resize(n))
            {
                return -1;
            }
        }
        __m_Data[++__m_pos] = pData;
        DEBUG("memsize : [%u], pos : [%d], p = [0X%08X]
    ", __m_memsize, __m_pos, (unsigned int)__m_Data[__m_pos]);
    
        return 0;
    }

    1.7)清空栈数据函数

    //清空栈,需要指定回收元素数据的函数,
    //否则无法知道如何回收由用户申请的内存空间
    template<typename T> int ClsStack<T>::clear(void (*F)(T *))
    {
        if(NULL == F && __m_pos >= 0)
        {
            return -1;
        }
        if(NULL != __m_Data && 0 != __m_memsize)
        {
            for(int i = 0; i <= __m_pos; i++)
            {
                F(__m_Data[i]);
                __m_Data[i] = NULL;
            }
            delete __m_Data;
        }
        __m_Data = NULL;
        __m_pos = -1;
        __m_memsize = 0;
    }

    1.8)调试辅助函数

    //输出栈的内存状态,调试时使用
    template<typename T> void ClsStack<T>::printStack(T * p[], int pos)
    {
        int i = 0;
        for(i = 0; i <= pos; i++)
        {
            printf("[%08u] = [0X%08X]
    ", i, NULL == p ? 0 : p[i]);
        }
        printf("----------------------------
    ");
    }

    1.9)测试代码

    //test 函数定义
    #define TEST_EQ(a, b)
        do{
            if(a == b)
            {
                printf("33[0;32m[SUCCESS %5d]33[0m
    ", __LINE__);
            }
            else
            {
                printf("33[0;31m[FAILD   %5d]33[0m
    ", __LINE__);
            }
        }while(0)
    
    int main()
    {
        ClsStack<int> objStack;
        int x = 10;
        int * p = &x;
    
        //向栈内压入数据
        objStack.push(p);
        int i = 0;
        for(i = 0; i <= 10; i++)
        {
            int * z = new int;
            *z = i;
            objStack.push(z);
        }
        //开始弹出数据
        for(i = 10; i >= 0; i--)
        {
            int * z = NULL;
            objStack.pop(&z);
            if(NULL == z)
            {
                printf("z == NULL
    ");
                continue;
            }
            //测试弹出的数据和压入的数据是否一致
            TEST_EQ(i, *z);
            delete z;
        }
        int * g = NULL;
        objStack.pop(&g);
        TEST_EQ(x, *g);
    }

    完整代码如下(折叠了) :

      1 /*
      2  * =====================================================================================
      3  *
      4  *       Filename:  stack.cpp
      5  *
      6  *    Description:  a template stack library
      7  *
      8  *        Version:  1.0
      9  *        Created:  10/13/2016 09:52:46 AM
     10  *       Revision:  none
     11  *       Compiler:  gcc
     12  *
     13  *         Author:  YOUR NAME (fengbohello@foxmail.com), 
     14  *   Organization:  
     15  *
     16  * =====================================================================================
     17  */
     18 #include <stdio.h>
     19 #include <string.h>
     20 
     21 //一个调试开关,如果要看调试信息,就把这个开关的注释去掉
     22 //#define USEDEBUG
     23 
     24 //如果调试开关打开了,就定义好调试的输出函数(其实是个宏),
     25 #ifdef USEDEBUG
     26 #define DEBUG(fmt, arg...)
     27     do{
     28         printf("%s %d %s() : ", __FILE__, __LINE__, __func__);
     29         printf(fmt, ##arg);
     30     }while(0)
     31 #else
     32 //如果没有打开,这个函数什么也不做
     33 #define DEBUG(fmt, arg...)
     34 #endif
     35 
     36 //定义模版类 ClsStack
     37 template<typename T> class ClsStack
     38 {
     39     //这个类的=型私有数据,主要用于对栈的内存分配进行管理,
     40     //用户不需要关心内存,只需要调用对外提供的几个方法就可以了
     41     private :
     42         T ** __m_Data;//存储数据的内存开始地址
     43         int  __m_pos;//记录栈尾的位置,插入数据时插入这个位置
     44         int  __m_memsize;//记录内存的总数
     45 
     46     protected :
     47         //重新分配内存空间,可以减小,也可以增大
     48         int __resize(int n);
     49 
     50         //获取给定参数的双倍内存,其实主要目的是防止参数是0
     51         int __doublesize(int n);
     52 
     53     public :
     54         ClsStack(int n = 0);
     55         ~ClsStack();
     56 
     57         //弹出栈顶
     58         int  pop (T ** ppData);
     59 
     60         //获取栈顶元素,但是不弹出
     61         int  top (T ** ppData);
     62 
     63         //向栈添加数据
     64         int  push(T * pData);
     65 
     66         //清空整个栈的数据
     67         int clear(void (*)(T*));
     68 
     69         //输出整个栈的数据,用于调试
     70         void printStack(T * p[], int pos);
     71 };
     72 
     73 //构造函数
     74 //默认参数值是0
     75 //参数非零时的作用是用于初始化栈空间的大小
     76 template<typename T> ClsStack<T>::ClsStack(int n)
     77 {
     78     __m_Data = NULL;
     79     __m_pos = -1;
     80     __m_memsize = 0;
     81 
     82     if(0 != n)
     83     {
     84         __m_Data = new T * [n];
     85         if(NULL != __m_Data)
     86         {
     87             __m_memsize = n;
     88         }
     89     }
     90 }
     91 
     92 //析构函数
     93 //在栈对象被销毁时,需要把申请的内存空间释放
     94 template<typename T> ClsStack<T>::~ClsStack()
     95 {
     96     if(NULL != __m_Data)
     97     {
     98         delete __m_Data;
     99         __m_Data = NULL;
    100     }
    101     __m_pos = -1;
    102     __m_memsize = 0;
    103 }
    104 
    105 //计算新的内存空间
    106 //当参数是0的时候,指定内存空间是1
    107 //参数不是0的时候,内存加倍
    108 template<typename T> int ClsStack<T>::__doublesize(int n)
    109 {
    110     int x = 0;
    111     if(0 == n)
    112     {
    113         x = 1;
    114     }
    115     else
    116     {
    117         x = n * 2;
    118     }
    119 
    120     return x;
    121 }
    122 
    123 //重新设定栈的大小
    124 //就是扩展当前的内存容量到指定的大小
    125 template<typename T> int ClsStack<T>::__resize(int n)
    126 {
    127     T ** p = new T * [n];
    128     if(NULL == p)
    129     {
    130         return -1;
    131     }
    132     memset(p, 0, sizeof(T *) * (n));
    133     if(NULL != __m_Data)
    134     {
    135         //printStack(__m_Data, __m_pos);
    136         if( NULL == memcpy(p, __m_Data, __m_memsize * sizeof(T *)))
    137         {
    138             DEBUG("memcpy faild
    ");
    139             delete p;
    140             return -1;
    141         }
    142         //printStack(p, __m_pos);
    143         delete __m_Data;
    144     }
    145     __m_Data = p;
    146     __m_memsize = n;
    147 
    148     return 0;
    149 }
    150 
    151 //弹出数据
    152 //数据通过参数指定的指针返回
    153 template<typename T> int ClsStack<T>::pop(T ** ppData)
    154 {
    155     if(NULL == ppData)
    156     {
    157         return -1;
    158     }
    159     int r = 0;
    160     if(-1 == __m_pos)
    161     {
    162         *ppData = NULL;
    163         r = -1;
    164     }
    165     else
    166     {
    167         *ppData = __m_Data[__m_pos --];
    168         r = 0;
    169         DEBUG("memsize : [%u], pos : [%d], p = [0X%08X]
    ", __m_memsize, __m_pos + 1, (unsigned int)*ppData);
    170     }
    171 
    172     return r;
    173 }
    174 
    175 //获取栈顶元素,并不弹出
    176 template<typename T> int ClsStack<T>::top(T ** ppData)
    177 {
    178     if(NULL == ppData)
    179     {
    180         return -1;
    181     }
    182     int r = 0;
    183     if(-1 == __m_pos)
    184     {
    185         *ppData = NULL;
    186         r = -1;
    187     }
    188     else
    189     {
    190         *ppData = __m_Data[__m_pos];
    191         r = 0;
    192     }
    193 
    194     return r;
    195 }
    196 
    197 //向栈压入元素
    198 //栈会自己判断内存,如果内存不足会自动增加内存
    199 template<typename T> int ClsStack<T>::push(T * pData)
    200 {
    201     if(__m_pos + 1 >= __m_memsize)
    202     {
    203         int n = __doublesize(__m_memsize);
    204         if(0 != __resize(n))
    205         {
    206             return -1;
    207         }
    208     }
    209     __m_Data[++__m_pos] = pData;
    210     DEBUG("memsize : [%u], pos : [%d], p = [0X%08X]
    ", __m_memsize, __m_pos, (unsigned int)__m_Data[__m_pos]);
    211 
    212     return 0;
    213 }
    214 
    215 //清空栈,需要指定回收元素数据的函数,
    216 //否则无法知道如何回收由用户申请的内存空间
    217 template<typename T> int ClsStack<T>::clear(void (*F)(T *))
    218 {
    219     if(NULL == F && __m_pos >= 0)
    220     {
    221         return -1;
    222     }
    223     if(NULL != __m_Data && 0 != __m_memsize)
    224     {
    225         for(int i = 0; i <= __m_pos; i++)
    226         {
    227             F(__m_Data[i]);
    228             __m_Data[i] = NULL;
    229         }
    230         delete __m_Data;
    231     }
    232     __m_Data = NULL;
    233     __m_pos = -1;
    234     __m_memsize = 0;
    235 }
    236 
    237 //输出栈的内存状态,调试时使用
    238 template<typename T> void ClsStack<T>::printStack(T * p[], int pos)
    239 {
    240     int i = 0;
    241     for(i = 0; i <= pos; i++)
    242     {
    243         printf("[%08u] = [0X%08X]
    ", i, NULL == p ? 0 : p[i]);
    244     }
    245     printf("----------------------------
    ");
    246 }
    247 
    248 
    249 //test 函数定义
    250 #define TEST_EQ(a, b)
    251     do{
    252         if(a == b)
    253         {
    254             printf("33[0;32m[SUCCESS %5d]33[0m
    ", __LINE__);
    255         }
    256         else
    257         {
    258             printf("33[0;31m[FAILD   %5d]33[0m
    ", __LINE__);
    259         }
    260     }while(0)
    261 
    262 int main()
    263 {
    264     ClsStack<int> objStack;
    265     int x = 10;
    266     int * p = &x;
    267 
    268     //向栈内压入数据
    269     objStack.push(p);
    270     int i = 0;
    271     for(i = 0; i <= 10; i++)
    272     {
    273         int * z = new int;
    274         *z = i;
    275         objStack.push(z);
    276     }
    277     //开始弹出数据
    278     for(i = 10; i >= 0; i--)
    279     {
    280         int * z = NULL;
    281         objStack.pop(&z);
    282         if(NULL == z)
    283         {
    284             printf("z == NULL
    ");
    285             continue;
    286         }
    287         //测试弹出的数据和压入的数据是否一致
    288         TEST_EQ(i, *z);
    289         delete z;
    290     }
    291     int * g = NULL;
    292     objStack.pop(&g);
    293     TEST_EQ(x, *g);
    294 }
    View Code

    2、运行结果

      2.1、编译

    g++ -g  -c -o stack.o stack.cpp -Wall -I./
    g++ -g  -o stack stack.o -Wall -I./ 

      2.2、运行结果

    $ ./stack 
    [SUCCESS   288]
    [SUCCESS   288]
    [SUCCESS   288]
    [SUCCESS   288]
    [SUCCESS   288]
    [SUCCESS   288]
    [SUCCESS   288]
    [SUCCESS   288]
    [SUCCESS   288]
    [SUCCESS   288]
    [SUCCESS   288]
    [SUCCESS   293]

      


    本文同步发表于博客园:http://www.cnblogs.com/fengbohello/p/4547598.html

    作者: 风波

    mail: fengbohello@foxmail.com

  • 相关阅读:
    操作系统设计与实现(二)
    SpringCloud(八)Consul的微服务注册
    图的实现(邻接矩阵)及DFS、BFS
    SpringCloud(七)服务注册之Consul的简介和原理
    Mybatis笔记目录(6天)
    Mybatis学习笔记——day02
    C语言教程Day01
    Linux C/C++方向开发(13周学习路线)
    基于Java的实验室预约管理系统
    基于Android的高校学生考勤系统的设计与实现
  • 原文地址:https://www.cnblogs.com/fengbohello/p/4547598.html
Copyright © 2011-2022 走看看