这个版本是上个版本的加强版,上个版本的代码: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()
#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 = );
~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 = -;
__m_memsize = ; if( != 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 = -;
__m_memsize = ;
}

1.5)内存控制函数

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

1.6)栈操作函数的实现

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

1.7)清空栈数据函数

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

1.8)调试辅助函数

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

1.9)测试代码

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

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

 /*
* =====================================================================================
*
* Filename: stack.cpp
*
* Description: a template stack library
*
* Version: 1.0
* Created: 10/13/2016 09:52:46 AM
* Revision: none
* Compiler: gcc
*
* Author: YOUR NAME (fengbohello@foxmail.com),
* Organization:
*
* =====================================================================================
*/
#include <stdio.h>
#include <string.h> //一个调试开关,如果要看调试信息,就把这个开关的注释去掉
//#define USEDEBUG //如果调试开关打开了,就定义好调试的输出函数(其实是个宏),
#ifdef USEDEBUG
#define DEBUG(fmt, arg...)\
do{\
printf("%s %d %s() : ", __FILE__, __LINE__, __func__);\
printf(fmt, ##arg);\
}while()
#else
//如果没有打开,这个函数什么也不做
#define DEBUG(fmt, arg...)
#endif //定义模版类 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 = );
~ClsStack(); //弹出栈顶
int pop (T ** ppData); //获取栈顶元素,但是不弹出
int top (T ** ppData); //向栈添加数据
int push(T * pData); //清空整个栈的数据
int clear(void (*)(T*)); //输出整个栈的数据,用于调试
void printStack(T * p[], int pos);
}; //构造函数
//默认参数值是0
//参数非零时的作用是用于初始化栈空间的大小
template<typename T> ClsStack<T>::ClsStack(int n)
{
__m_Data = NULL;
__m_pos = -;
__m_memsize = ; if( != n)
{
__m_Data = new T * [n];
if(NULL != __m_Data)
{
__m_memsize = n;
}
}
} //析构函数
//在栈对象被销毁时,需要把申请的内存空间释放
template<typename T> ClsStack<T>::~ClsStack()
{
if(NULL != __m_Data)
{
delete __m_Data;
__m_Data = NULL;
}
__m_pos = -;
__m_memsize = ;
} //计算新的内存空间
//当参数是0的时候,指定内存空间是1
//参数不是0的时候,内存加倍
template<typename T> int ClsStack<T>::__doublesize(int n)
{
int x = ;
if( == n)
{
x = ;
}
else
{
x = n * ;
} return x;
} //重新设定栈的大小
//就是扩展当前的内存容量到指定的大小
template<typename T> int ClsStack<T>::__resize(int n)
{
T ** p = new T * [n];
if(NULL == p)
{
return -;
}
memset(p, , 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\n");
delete p;
return -;
}
//printStack(p, __m_pos);
delete __m_Data;
}
__m_Data = p;
__m_memsize = n; return ;
} //弹出数据
//数据通过参数指定的指针返回
template<typename T> int ClsStack<T>::pop(T ** ppData)
{
if(NULL == ppData)
{
return -;
}
int r = ;
if(- == __m_pos)
{
*ppData = NULL;
r = -;
}
else
{
*ppData = __m_Data[__m_pos --];
r = ;
DEBUG("memsize : [%u], pos : [%d], p = [0X%08X]\n", __m_memsize, __m_pos + , (unsigned int)*ppData);
} return r;
} //获取栈顶元素,并不弹出
template<typename T> int ClsStack<T>::top(T ** ppData)
{
if(NULL == ppData)
{
return -;
}
int r = ;
if(- == __m_pos)
{
*ppData = NULL;
r = -;
}
else
{
*ppData = __m_Data[__m_pos];
r = ;
} return r;
} //向栈压入元素
//栈会自己判断内存,如果内存不足会自动增加内存
template<typename T> int ClsStack<T>::push(T * pData)
{
if(__m_pos + >= __m_memsize)
{
int n = __doublesize(__m_memsize);
if( != __resize(n))
{
return -;
}
}
__m_Data[++__m_pos] = pData;
DEBUG("memsize : [%u], pos : [%d], p = [0X%08X]\n", __m_memsize, __m_pos, (unsigned int)__m_Data[__m_pos]); return ;
} //清空栈,需要指定回收元素数据的函数,
//否则无法知道如何回收由用户申请的内存空间
template<typename T> int ClsStack<T>::clear(void (*F)(T *))
{
if(NULL == F && __m_pos >= )
{
return -;
}
if(NULL != __m_Data && != __m_memsize)
{
for(int i = ; i <= __m_pos; i++)
{
F(__m_Data[i]);
__m_Data[i] = NULL;
}
delete __m_Data;
}
__m_Data = NULL;
__m_pos = -;
__m_memsize = ;
} //输出栈的内存状态,调试时使用
template<typename T> void ClsStack<T>::printStack(T * p[], int pos)
{
int i = ;
for(i = ; i <= pos; i++)
{
printf("[%08u] = [0X%08X]\n", i, NULL == p ? : p[i]);
}
printf("----------------------------\n");
} //test 函数定义
#define TEST_EQ(a, b)\
do{\
if(a == b)\
{\
printf("\033[0;32m[SUCCESS %5d]\033[0m\n", __LINE__);\
}\
else\
{\
printf("\033[0;31m[FAILD %5d]\033[0m\n", __LINE__);\
}\
}while() int main()
{
ClsStack<int> objStack;
int x = ;
int * p = &x; //向栈内压入数据
objStack.push(p);
int i = ;
for(i = ; i <= ; i++)
{
int * z = new int;
*z = i;
objStack.push(z);
}
//开始弹出数据
for(i = ; i >= ; i--)
{
int * z = NULL;
objStack.pop(&z);
if(NULL == z)
{
printf("z == NULL\n");
continue;
}
//测试弹出的数据和压入的数据是否一致
TEST_EQ(i, *z);
delete z;
}
int * g = NULL;
objStack.pop(&g);
TEST_EQ(x, *g);
}

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 ]
[SUCCESS ]
[SUCCESS ]
[SUCCESS ]
[SUCCESS ]
[SUCCESS ]
[SUCCESS ]
[SUCCESS ]
[SUCCESS ]
[SUCCESS ]
[SUCCESS ]
[SUCCESS ]

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

作者: 风波

mail: fengbohello@foxmail.com

纪念逝去的岁月——C++实现一个栈(使用类模板)的更多相关文章

  1. 纪念逝去的岁月——C++实现一个栈

    1.代码 2.运行结果 1.代码 stack.cpp #include <stdio.h> #include <string.h> class ClsStack { priva ...

  2. 纪念逝去的岁月——C++实现一个队列(使用类模板)

    1.代码 2.运行结果 1.代码 #include <stdio.h> #include <string.h> template <typename T> clas ...

  3. 纪念逝去的岁月——C/C++排序二叉树

    1.代码 2.运行结果 3.分析 1.代码 #include <stdio.h> #include <stdlib.h> typedef struct _Node { int ...

  4. 纪念逝去的岁月——C/C++二分查找

    代码 #include <stdio.h> int binarySearch(int iList[], int iNum, int iX, int * pPos) { if(NULL == ...

  5. 纪念逝去的岁月——C/C++快速排序

    快速排序 代码 #include <stdio.h> void printList(int iList[], int iLen) { ; ; i < iLen; i++) { pri ...

  6. 纪念逝去的岁月——C/C++交换排序

    交换排序 代码 #include <stdio.h> void printList(int iList[], int iLen) { ; ; i < iLen; i++) { pri ...

  7. 纪念逝去的岁月——C/C++选择排序

    选择排序 代码 #include <stdio.h> void printList(int iList[], int iLen) { ; ; i < iLen; i++) { pri ...

  8. 纪念逝去的岁月——C/C++冒泡排序

    冒泡排序 代码 #include <stdio.h> void printList(int iList[], int iLen) { ; ; i < iLen; i++) { pri ...

  9. 纪念逝去的岁月——C/C++字符串回文

    判断字符串是否是回文: 1. 输入:hello world dlrow olleh 输出:1 2. 输入:nihao hello 输出:0 代码 #include <stdio.h> #i ...

随机推荐

  1. NBU官方Doc網址https://www.veritas.com/support/en_US/article.DOC5332

    NBU(NetBackup) 7.0之後的版本官方文檔鏈接地址: https://www.veritas.com/support/en_US/article.DOC5332

  2. Android系统介绍与框架(转)

    一.Andriod是什么? Android系统是Google开发的一款开源移动OS,Android中文名被国内用户俗称“安卓”.Android操作系统基于Linux内核设计,使用了Google公司自己 ...

  3. 小甲鱼PE详解之IMAGE_NT_HEADERS结构定义即各个属性的作用(PE详解02)

    PE Header 是PE相关结构NT映像头(IMAGE_NT_HEADER)的简称,里边包含着许多PE装载器用到的重要字段.下边小甲鱼将为大家详细讲解哈~ (视频教程:http://fishc.co ...

  4. Servlet域对象ServletContext小应用------计算网站访问量

    package cn.yzu; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.Servlet ...

  5. js实现页面的自动读秒跳转

    <!-- 代码片段A --> <!-- 倒计时跳转 --> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Trans ...

  6. mysql LAST_INSERT_ID 使用与注意事项

    在使用MySQL时,若表中含自增字段(auto_increment类型),则向表中insert一条记录后,可以调用last_insert_id()来获得最近insert的那行记录的自增字段值 $mdb ...

  7. 阿里云Linux系统挂载数据盘

    Linux云服务器数据盘未做分区和格式化,我们可以根据以下步骤进行分区以及格式化操作. 目录 [隐藏]  1 查看数据盘 2 对数据盘进行分区 3 查看新的分区 4 格式化新分区 5 添加分区信息 6 ...

  8. AOP动态代理解析4-代理的创建

    做完了增强器的获取后就可以进行代理的创建了 AnnotationAwareAspectJAutoProxyCreator->postProcessAfterInitialization-> ...

  9. poj 1321 棋盘问题

    八皇后问题变形,回溯法. #include <cstdio> #include <cstring> #include <iostream> using namesp ...

  10. Angular JS学习之指令

    1.Angular JS通过称为指令的新属性来扩展HTML:通过内置的指令来为应用添加功能: 2.AngularJS指令:AngularJS指令是扩展的HTML属性,带有前缀ng-: **ng-app ...