今天用链表实现了栈的基本操作。其实,单链表本身就具有栈的特性,因而可以直接用不带头指针的单链表来模拟一个栈的操作。为了更好体现栈的特性和操作方便,将单链表封装到一个名为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("\nStack:InitStack:分配内存失败!\n");
        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("\nStack:Pop:栈空,返回!\n");
        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\t",p->data);
        p=p->next;
    }
}

主函数中有一个测试用函数:

#include "Stack.h"

void testStack();
int main()
{
    printf("\n");
    testStack();
    return 0;
}

void testStack()
{
    printf("\n");
    Stack *ps=InitStack();
    int temp;
    int icount;
    if(ps==NULL)
    {
        perror("\nmain:testStack:栈为空!\n");
    }
    while(scanf("%d",&temp))
    {
        icount=Push(ps,temp);
    }
    printf("\n");
    StackTraverse(ps);
    printf("\n");
    while(IsEmpty(ps)==0)
    {
        printf("%d\t",ps->top->data);
        Pop(ps);
    }

}

下面是一张调试结果,输入一个随意的非数字字符即可结束输入。

QQ截图20151010123115

欢迎交流!

posted on 2015-10-10 12:32  那个十四号  阅读(229)  评论(0编辑  收藏  举报