简单数据结构之栈

——引子

栈是系统软件必不可少的数据结构,其应用十分的广泛,例如:储存管理、函数调用以及表达式求值等,都离不开栈这个数据结构。

另外,深度优先搜索算法也需要借助栈来完成。

那么,栈到底是一种怎样的结构呢?

栈的特点

栈其实也是线性表中的一种,不过,它是作为线性表中比较特例的存在。

这种结构,只允许在栈的一端进行操作,这个位置,也被称为栈顶!

对于栈的一切操作,例如增、删、查等,都只能在栈顶进行,对于栈其他位置的元素,没有影响。

所以,这也就造成了栈最大的特点:后进先出!

对于栈的理解

对于栈,我们可以将其想象成一个瓶子,而元素,就是瓶子中的水,瓶口就相当于是栈顶,瓶底相当于栈底。

当一个元素进入栈时,就像水一样,直接进入瓶子的最底层,而想要倒水出来,那最先出来的只能是上层的水。

所以,将栈这个结构,当作一个水瓶,是在好不过的了~

还有,关于栈元素的出栈顺序,利用的就是我们的卡特兰数,对于卡特兰数,在这里我就不做过多的解释,想要了解的小伙伴们,可以自己找找相关的书籍~

在为大家大概的讲明栈的逻辑意义之后,就是我们的重头戏了,下面就让我们一起,看看栈结构,到底是如何实现的~

栈的实现

既然栈也是一种特别的线性表,那么在之前的了解之中,我们已经知道,线性表分为两种,一种是顺序的,一种是链式的。

那么,既然栈作为一个线性表,那肯定也有两种实现的形式,接下来,就让我们一起看看,这两种形式的栈,有何不同之处!

顺序栈

使用顺序存储的方式实现栈结构与实现顺序表的结构类似,不同的是,对于栈内元素的操作,我们只能从栈顶进行。

由于顺序表中,在尾部插入和删除元素比较容易,所以,在下面的代码中,我们将表的尾部当作栈顶,具体实现如下:

类型定义
typedef int data;

typedef struct{
    int top;
    int capacity;
    data * array;
}stack;
//这里利用typedef关键字,可以将代码的可重用性提高一点,想要转变数据类型时,直接改变就行,数据类型可以时结构体!
初始化
stack * init_stack(stack * p, int d){
    p->top = 0;
    p->capacity = d?d:8;
    p->array = (data *)malloc(sizeof(data) * p->capacity);
    return p;
}//初始化栈
销毁
void destory_stack(stack * p){
    free(p->array);
}//销毁栈
判断栈是否为空
_Bool isEmpty_stack(stack * p){
    return p->top == 0;
}//判断栈是否为空
扩展空间
stack * extend_stack(stack * p){
    int i = 0;
    data * new_array = (data *)malloc(sizeof(data) * p->capacity * 2);
    for(i = 0; i < p->top; i++){
        new_array[i] = p->array[i];
    }
    free(p->array);
    p->array = new_array;
    return p;
}//空间扩展
入栈
stack * push_stack(stack * p, data d){
    if(p->top == p->capacity){
        extend_stack(p);
    }
    p->array[p->top++] = d;
    return p;
}//入栈
弹栈
stack * pop_stack(stack * p){
    if(p->top == 0){
        return (void *)0;
    }
    p->top--;
    return p;
}//弹栈
读取栈顶元素
stack * read_stack(stack * p, data * da){
    if(p->top == 0){
        return (void *)0;
    }
    * da = p->array[p->top - 1];
    return p;
}//读取栈顶元素
测试数据
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
int main()
{
    stack s;
    init_stack(&s,4);
    if(isEmpty_stack(&s)){
        printf("栈为空!\n");
    }
    printf("开始入栈操作:1,2,3,4,5\n");
    push_stack(&s,1);
    push_stack(&s,2);
    push_stack(&s,3);
    push_stack(&s,4);
    push_stack(&s,5);
    printf("入栈操作完成!\n");
    while(!isEmpty_stack(&s)){
        data d;
        read_stack(&s,&d);
        printf("此时栈顶元素是:%d\n",d);
        printf("弹栈操作执行!\n");
        pop_stack(&s);
    }
    if(isEmpty_stack(&s)){
        printf("栈为空!\n");
    }
    destory_stack(&s);
    return 0;
}
结果

在这里插入图片描述

链式栈

使用链式存储的方式实现栈,由于链表的头插和头删比较快,所以我们将链表的表头当作是栈顶,具体实现如下:

在这里插入代码片

类型定义
typedef int Data;

typedef struct N{
    Data data;
    struct N * next;
}Node;

typedef struct{
    Node * top;
    int size;
}Link_stack;
//这里将数据域类型起别名的原因和上面的顺序栈相同,都是为了代码可重用!
创建节点
Node * make_node(Data d){
    Node * new_node = (Node *) malloc(sizeof(Data));
    new_node->data = d;
    new_node->next = (void *)0;
    return new_node;
}//创建节点
初始化
Link_stack * init_stack(Link_stack * p){
    p->size = 0;
    p->top = (void *)0;
    return p;
}//初始化
销毁
void destory_stack(Link_stack * p){
    while(p->top){
        Node * del = p->top;
        p->top = p->top->next;
        free(del);
    }

}//销毁栈
判断栈是否为空
_Bool isEmpty_stack(Link_stack * p){
    return p->top == (void *)0;
}//判断栈是否为空
入栈
Link_stack * push_stack(Link_stack * p, Data d){
    Node * new_node = make_node(d);
    if(!new_node){
        return (void *)0;
    }
    new_node->next = p->top;
    p->top = new_node;
    p->size++;
    return p;
}//入栈
弹栈
Link_stack * pop_stack(Link_stack * p){
    if(p->size == 0){
        return (void *)0;
    }
    Node * del = p->top;
    p->top = p->top->next;
    free(del);
    p->size--;
    return p;
}//弹栈
读取栈顶元素
Link_stack * read_stack(Link_stack * p, Data * d){
    if(p->size == 0){
        return (void *)0;
    }
    *d = p->top->data;
    return p;
}//读取栈顶元素
测试数据
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
int main()
{
    int a[5] = {1,2,3,4,5};
    int i = 0;
    Link_stack s;
    init_stack(&s);
    if((&s)->size == 0){
        printf("栈创建成功!\n");
    }
    printf("需要入栈的元素有:1,2,3,4,5\n");
    for(i = 0; i < 5; i++){
        printf("此时入栈的元素是:%d\n",a[i]);
        push_stack(&s,a[i]);
        if(!isEmpty_stack(&s)){
            printf("入栈成功!\n");
        }
    }
    while((&s)->top){
        Data d;
        printf("此时栈顶元素是:");
        read_stack(&s,&d);
        printf("%d\n",d);
        Link_stack * x = pop_stack(&s);
        if(x != (void *)0){
            printf("弹栈成功!\n");
        }
    }
    destory_stack(&s);
    return 0;
}
结果

在这里插入图片描述

总结

这次给大家带来的就是这么多了,下一次窝瓜将给大家带来队列的简单实现~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值