这个版本是上个版本的加强版,上个版本的代码: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. zTree v3.5配置

    页面 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ZTree3.aspx ...

  2. linux的<pthread.h>

    转自:http://blog.sina.com.cn/s/blog_66cc44d00100in5b.html Linux系统下的多线程遵循POSIX线程接口,称为pthread.编写Linux下的多 ...

  3. 制作U盘启动系统盘

    下载ULtraISO,安装之后,先打开一个iso系统文件,然后选中菜单“启动”下的“写入硬盘映像”

  4. Android adb的使用

    参考:http://blog.csdn.net/veryitman/article/details/6437090 1. 进入shell 进入设备shell adb shell 2. 安装 apk & ...

  5. HDU 4251 The Famous ICPC Team Again 主席树

    The Famous ICPC Team Again Problem Description   When Mr. B, Mr. G and Mr. M were preparing for the ...

  6. Codeforces Round #369 (Div. 2) D. Directed Roads dfs求某个联通块的在环上的点的数量

    D. Directed Roads   ZS the Coder and Chris the Baboon has explored Udayland for quite some time. The ...

  7. 为什么要使用 Node.js

    这是一个移动端工程师涉足前端和后端开发的学习笔记,如有错误或理解不到位的地方,万望指正. Node.js 是什么 传统意义上的 JavaScript 运行在浏览器上,这是因为浏览器内核实际上分为两个部 ...

  8. JFreeChart 使用一 饼图之高级特性

    原文链接:http://www.cnblogs.com/jtmjx/archive/2013/04/23/jfreechart_advantage.html 本文主要讲解JFreeChart中饼图的一 ...

  9. Linux学习笔记(21) Linux日志管理

    1. 简介 (1) 日志服务 在CentOS 6.x中日志服务已经由rsyslogd取代了原先的syslogd服务.rsyslogd日志服务更加先进,功能更多.但是不论该服务的使用,还是日志文件的格式 ...

  10. 用户视角 vs 系统视角 看性能

    如何评价性能的优劣: 用户视角 vs. 系统视角 对于最终用户(End-User)来说,评价系统的性能好坏只有一个字——“快”.最终用户并不需要关心系统当前的状态——即使系统这时正在处理着成千上万的请 ...