栈的应用场景非常多,系统的函数调用栈、逆序匹配、数制转换、迷宫求解等等,本文介绍介绍使用链表实现、具有通用性的栈
功能需求
- 判空
- 判满
- 入栈
- 出栈
- 销毁栈
- 输出打印
数据结构
使用预编译宏作为开关,实现数据结构成员通用性
/*------------------common linked stack Start----------------*/
#define TEST_COM_LNK_STACK 1
#define MAZE_STACK_SUPPORT 0
typedef struct stCustomData {
/*customized member here*/
/*...*/
/*customized member here*/
#if TEST_COM_LNK_STACK
stElemtype_singleLL stData;
#elif MAZE_STACK_SUPPORT
stMazeNode stData;
#endif
}stCustomData, *pstCustomData;
typedef struct stComLnkStackNode {
stCustomData stElm;
stComLnkStackNode *pstNxt;
}stComLnkStackNode, *pstComLnkStackNode, **ppstComLnkStackNode;
typedef struct stComLnkStack {
PP_INT32 iSize;
PP_INT32 iVol;
pstComLnkStackNode pstTop;
pstComLnkStackNode pstBottom;
}stComLnkStack, *pstComLnkStack, **ppstComLnkStack;
/*------------------common linked stack End----------------*/
接口列表
为了提升性能,减少不必要的调用,使用宏替代函数实现判满、判空;同时为了让链式栈更具有通用性,尽量让用户(自己)能有更多精力去考虑业务而不是底层实现,也把内存申请封装成为了一个宏,所有的接口如下:
/*********************common linked stack Start*********************/
#define COM_LINK_GET_TOP(pstStk) ((pstStk)->pstTop)
#define COM_LINK_STACK_EMPTY(pstStk) (!(pstStk)->pstTop ? TRUE : FALSE)
#define COM_LINK_STACK_FULL(pstStk) ((pstStk)->iSize + 1 > (pstStk)->iVol ? TRUE : FALSE)
#define NULL_PTR(pstTmp) ((pstTmp) = NULL)
#define COM_LNK_STACK_NODE_MALLOC(pstCur) \
pstComLnkStackNode pstCur = (pstComLnkStackNode)malloc(sizeof(stComLnkStackNode));\
if (!(pstCur)) RET_LOCAL(enRetVal = ERR_MEMORY_ALLOC);\
memset((pstCur),0,sizeof(stComLnkStackNode));
enErr_val CreateComLnkStack(ppstComLnkStack ppstStk, int iVolume);
enErr_val PushComLnkStack(const pstComLnkStack pstStk, const pstComLnkStackNode pstElm);
enErr_val PopComLnkStack(const pstComLnkStack pstStk, ppstComLnkStackNode ppstElm);
enErr_val DestroyComLnkStack(ppstComLnkStack ppstStk);
void PrintComLnkStack(const pstComLnkStack pstStk);
/*********************common linked stack End*********************/
接口实现
创建和初始化链式栈
enErr_val CreateComLnkStack(ppstComLnkStack ppStk, int iVol) {
REG_FUNC_NAME("CreateComLnkStack");
enErr_val enRetVal = ERR_SUCCESS;
if (*(ppStk)) *ppStk = NULL;
*ppStk = (pstComLnkStack)malloc(iVol * sizeof(stComLnkStack));
if (!(*ppStk)) RET_LOCAL(enRetVal = ERR_MEMORY_ALLOC);
(*ppStk)->iVol = iVol;
(*ppStk)->iSize = 0;
(*ppStk)->pstTop = NULL;
(*ppStk)->pstBottom = NULL;
RET_LOCAL(enRetVal)
}
入栈操作
入栈前需要判满,若栈满则退出并报错;
enErr_val PushComLnkStack(const pstComLnkStack pStk, const pstComLnkStackNode pElm) {
REG_FUNC_NAME("PushComLnkStack");
enErr_val enRetVal = ERR_SUCCESS;
if (!pStk || !pElm) RET_LOCAL(enRetVal = ERR_INVALID_PARAMETER);
if (COM_LINK_STACK_FULL(pStk)) RET_LOCAL(enRetVal = ERR_STACK_FULL);
pElm->pstNxt = COM_LINK_GET_TOP(pStk);
pStk->pstTop = pElm;
++pStk->iSize;
RET_LOCAL(enRetVal)
}
出栈操作
出栈前要判空,若栈空则退出并报错;
enErr_val PopComLnkStack(const pstComLnkStack pStk, ppstComLnkStackNode ppElm) {
REG_FUNC_NAME("PopComLnkStack");
enErr_val enRetVal = ERR_SUCCESS;
if (!pStk || !ppElm) RET_LOCAL(enRetVal = ERR_INVALID_PARAMETER);
if (COM_LINK_STACK_EMPTY(pStk)) RET_LOCAL(enRetVal = ERR_STACK_EMPTY);
(*ppElm) = COM_LINK_GET_TOP(pStk);
pStk->pstTop = (*ppElm)->pstNxt;
--pStk->iSize;
RET_LOCAL(enRetVal)
}
销毁栈
enErr_val DestroyComLnkStack(ppstComLnkStack ppStk) {
REG_FUNC_NAME("DestroyComLnkStack");
enErr_val enRetVal = ERR_SUCCESS;
if (!(*ppStk)) RET_LOCAL(enRetVal = ERR_INVALID_PARAMETER);
pstComLnkStackNode stuff = NULL;
while (!COM_LINK_STACK_EMPTY(*ppStk)) {
PopComLnkStack(*ppStk, &stuff);
free(stuff);
}
NULL_PTR(stuff);
free(*ppStk);
PP_LOG("the stack is destory!\n");
RET_LOCAL(enRetVal)
}
打印输出
void PrintComLnkStack(const pstComLnkStack pStk) {
REG_FUNC_NAME("PrintComLnkStack");
if (!pStk) return;
pstComLnkStackNode pNode = COM_LINK_GET_TOP(pStk);
PP_INT32 i = 0;
while (pNode) {
#if TEST_COM_LNK_STACK
PP_LOG("%d-th:%d, pstNxt addr:%x\n",
++i, pNode->stElm.stData.iScores, pNode->pstNxt);
#endif
pNode = pNode->pstNxt;
}
}