05--栈的链式实现

281 阅读3分钟

# 05--栈的顺序存储中已经介绍了栈的相关特性,以及用顺序存储的方式设计了一个栈。这篇文章介绍栈的链式实现。

一、栈的特性

  • 1.栈是线性结构中的一个限定性数据结构,线性结构拥有的特性栈都拥有;
  • 2.栈的限定性特性是只能由栈顶入栈和出栈;
  • 3.栈的数据满足先进后出的原则。

二、栈的设计

结合栈先进后出,栈顶出入栈的特性和链式存储的特征,来设计一下栈的链式存储。

1.准备数据

定义一些状态和对一些数据类型进行重定义,方便在设计中的状态回调用数据类型的使用

#define OK 1

#define ERROR 0

#define TRUE 1

#define FALSE 0

#define MAXSIZE 20 /* 存储空间初始分配量 */

typedef int Status;

typedef int SElemType; /* SElemType类型根据实际情况而定,这里假设为int */

2.链式栈的结点

typedef struct StackNode
{
    SElemType data;
    struct StackNode *next;

}StackNode,*LinkStackPtr;

使用单向链表来设计链式实现,所以设计如上节点的数据结构,data是数据域,用来保存数据;next是指针域,指向下一节点。

3.栈的设计

typedef struct
{
    LinkStackPtr top;
    int count;

}LinkStack;

top永远指向栈顶,count记录栈的长度。

三、创建一个空栈

Status InitStack(LinkStack *S)
{
    S->top = NULL;
    S->count=0;
    return OK;
}

空栈时栈顶指针top指向NULL,栈的长度count为0

四、清空栈

Status ClearStack(LinkStack *S){
    LinkStackPtr p,q;
    p = S->top;

    while (p) {
        q = p;
        p = p->next;
        free(q);
    }

    S->count = 0;

    return OK;
}

链式栈清空时,需要将栈中所有节点的数据都释放,使得top指向NULL;并且栈的长度count为0

五、栈的判空

Status StackEmpty(LinkStack S){

    if (S.count == 0)
        return TRUE;
    else
        return FALSE;

}

栈为的判断既可以判断count为0,也可以判断top指向NULL

六、返回栈的长度

int StackLength(LinkStack S){

    return S.count;

}

七、返回栈顶数据

Status GetTop(LinkStack S,SElemType *e){

    if(S.top == NULL)
        return ERROR;
    else
        *e = S.top->data;
    return OK;
}

栈为时,无栈顶数据;否则取top的data即为栈顶数据。

八、入栈

Status Push(LinkStack *S, SElemType e){
    //创建新结点temp
    LinkStackPtr temp = (LinkStackPtr)malloc(sizeof(StackNode));
    //赋值
    temp->data = e;
    //把当前的栈顶元素赋值给新结点的直接后继, 参考图例第①步骤;
    temp->next = S->top;

    //将新结点temp 赋值给栈顶指针,参考图例第②步骤;
    S->top = temp;
    S->count++;

    return OK;
}
  • 1.入栈时,创建一个节点,设置数据,将新节点放在栈顶,加入链表即可;
  • 2.新节点的next指向旧栈顶,再将top指向新节点,使得新节点成为新的栈顶
  • 3.入栈后栈的长度加1

九、出栈

Status Pop(LinkStack *S,SElemType *e){

    LinkStackPtr p;

    if (StackEmpty(*S)) {
        return ERROR;
    }
    //将栈顶元素赋值给*e
    *e = S->top->data;

    //将栈顶结点赋值给p,参考图例①
    p = S->top;

    //使得栈顶指针下移一位, 指向后一结点. 参考图例②
    S->top= S->top->next;

    //释放p
    free(p);

    //个数--
    S->count--;

    return OK;
}
  • 1.空栈是不能出栈的;
  • 2.返回栈顶数据,让外部知道出栈的是什么;
  • 3.栈顶top向下移动一位,指向top->next
  • 4.释放旧的栈顶元素;
  • 5.栈的长度减1

十、遍历栈

Status StackTraverse(LinkStack S){
    LinkStackPtr p;
    p = S.top;

    while (p) {
        printf("%d ",p->data);
        p = p->next;
    }
    printf("\n");

    return OK;
}

栈的遍历和单向链表的遍历是一样的。

十一、总结

栈的链式实现使用了单向链表,在设计一个栈时,要遵循栈的限定性特征:

  • 1.先进后出
  • 2.只能从栈顶入栈和出栈。