今天用链表实现了栈的基本操作。其实,单链表本身就具有栈的特性,因而可以直接用不带头指针的单链表来模拟一个栈的操作。为了更好体现栈的特性和操作方便,将单链表封装到一个名为Stack的结构体中。其结构定义如下:
typedef int DATA; typedef struct _snode SNode; /*定义栈节点类型*/ typedef struct _snode { DATA data; SNode *next; }SNode; /*定义栈类型*/ typedef struct _stack { SNode *top; int _size;//当前栈中节点数目 }Stack,*LinkedStack;
可以看出,在Stack中,除了用一个链表头指针存储栈顶元素外,还有一个int型的变量_size,用来存储栈中节点数目。这样可以方便获得栈的相关信息,也可以用for循环遍历等。当然,这也会带来一个问题。即,因为_size对程序员是公开的,而不像在OOP中可以定义为私有域,因而错误地直接修改_size的值会给相关操作带来麻烦。(C语言中有什么实现结构体域私有的方法么,请赐教^0^)。
其实栈本身作为一种FIFO的数据结构,最重要的还是关注栈POP和PUSH吧。实际中的安全问题,需要根据具体情况作出判断。
此外,对于指针的判空,栈元素的判空等,遵循的原则应该是各负其责,实现层次调用。代码中有些地方判断可能有些多余。
上代码:
#include <stdio.h> #include <stdlib.h> #ifndef STACK_H_INCLUDED #define STACK_H_INCLUDED typedef int DATA; typedef struct _snode SNode; /*定义栈节点类型*/ typedef struct _snode { DATA data; SNode *next; }SNode; /*定义栈类型*/ typedef struct _stack { SNode *top; int _size;//当前栈中节点数目 }Stack,*LinkedStack; /*构造一个空栈,返回栈头指针*/ Stack *InitStack(); /*销毁一个栈*/ void DestroyStack(Stack *ps); /*把栈置空*/ void ClearStack(Stack *ps); /*判定是否为空栈*/ int IsEmpty(Stack *ps); /*返回栈大小*/ int GetSize(Stack *ps); /*返回栈顶元素*/ DATA GetTop(Stack *ps); /*元素入栈,返回栈中元素数目*/ int Push(Stack *ps,DATA d); /*元素出栈*/ DATA Pop(Stack *ps); /*遍历栈并访问visit函数*/ void StackTraverse(Stack *ps); #endif // STACK_H_INCLUDED
Stack.c
#include "Stack.h" /*构造一个空栈,返回栈头指针*/ Stack *InitStack() { Stack *ps; ps=(Stack*)malloc(sizeof(Stack)); if(ps==NULL) { perror(" Stack:InitStack:分配内存失败! "); return; } else { ps->_size=0; ps->top=NULL; return ps; } } /*销毁一个栈*/ void DestroyStack(Stack *ps) { if(ps==NULL)return; ClearStack(ps); free(ps); } /*把栈置空*/ void ClearStack(Stack *ps) { while(IsEmpty(ps)==0) { Pop(ps); } } /*判定是否为空栈*/ int IsEmpty(Stack *ps) { if(ps->top==NULL&&ps->_size==0) { return 1; } else if(ps->top==NULL&&ps->_size!=0) { ps->_size=0; return 1; } else if(ps->top!=NULL&&ps->_size==0) { ps->_size=CalcSize(ps->top); return 0; } return 0; } /*返回栈大小*/ int GetSize(Stack *ps) { return ps->_size; } /*重新计算栈大小,内部函数*/ int CalcSize(SNode *pn) { if(pn==NULL)return 0; SNode *p=pn; int i=0; while(p) { i++; p=p->next; } } /*返回栈顶元素*/ DATA GetTop(Stack *ps) { if(ps==NULL) return; if(IsEmpty(ps)!=0) return; return ps->top->data; } /*元素入栈,返回栈中元素数目*/ int Push(Stack *ps,DATA d) { if(ps==NULL)return; SNode *p; p=(SNode*)malloc(sizeof(SNode)); if(p) { p->data=d; p->next=ps->top; ps->top=p; ps->_size++; } return ps->_size; } /*元素出栈*/ DATA Pop(Stack *ps) { if(ps==NULL||IsEmpty(ps)) { perror(" Stack:Pop:栈空,返回! "); return; } SNode *p=ps->top; ps->top=p->next; ps->_size--; free(p); } void StackTraverse(Stack *ps) { if(ps==NULL)return; SNode *p=ps->top; while(p) { printf("%d ",p->data); p=p->next; } }
主函数中有一个测试用函数:
#include "Stack.h" void testStack(); int main() { printf(" "); testStack(); return 0; } void testStack() { printf(" "); Stack *ps=InitStack(); int temp; int icount; if(ps==NULL) { perror(" main:testStack:栈为空! "); } while(scanf("%d",&temp)) { icount=Push(ps,temp); } printf(" "); StackTraverse(ps); printf(" "); while(IsEmpty(ps)==0) { printf("%d ",ps->top->data); Pop(ps); } }
下面是一张调试结果,输入一个随意的非数字字符即可结束输入。
欢迎交流!