数据结构——栈

栈分为顺序栈和链式栈,顺序栈是有顺序表的方法实现栈的功能,而链式栈则是用链表的方法实现栈的功能。

顺序栈

结构体

typedef struct seqstack
{
    int *data;
    int maxlen;
    int top;
}seqstack_t;

其中,指针data可以当作数组名来使用,maxlen表示有效元素个数,也就是栈的长度,top是栈针,作用相当于顺序表中的last,始终代表最后一个有效元素的下标。

创建空栈

seqstack_t *CreateEpSeqStack(int len)
{
    seqstack_t *p = (seqstack_t *)malloc(sizeof(seqstack_t));
    if (p == NULL)
    {
        perror("create malloc error");
        return NULL;
    }
    p->maxlen = len;
    p->top = -1;
    p->data = (int *)malloc(sizeof(int) * len);
    if (p->data == NULL)
    {
        perror("data malloc error");
        return NULL;
    }
    return p;
}

和以往的顺序表和链表相同,创建无非开辟空间和初始化两步,对于顺序栈,空间的开辟也是开辟一个结构体类型大小的空间,但是还要开辟一个int类型的数组空间,开辟的大小取决于函数传入的参数len,也就是想要存放多少个数据。此时栈还没有存储任何数据,所以栈针top赋值为-1。

入栈

int PushStack(seqstack_t *p, int data)
{
    if (IsFullSeqStack(p))
    {
        perror("push error");
        return -1;
    }
    p->top++;
    p->data[p->top] = data;
    return 0;
}

入栈前,栈针指向入栈位置的前一位,入栈时先要将栈针向后移动一个数据的位置,然后在p->top位置直接入栈数据即可。入栈时首先要判断栈是否满,判断是否满的函数如下:

int IsFullSeqStack(seqstack_t *p)
{
    return p->top + 1 == p->maxlen;
}

出栈

int PopSeqStack(seqstack_t *p)
{
    if (IsEpSeqStack(p))
    {
        perror("empty");
        return -1;
    }
    p->top--;
    printf("%d  ",p->data[p->top + 1]);
    return 0;
}

出栈时先将栈针向下移动一位,然后输出栈针+1位置的数据,即p->data[p->top + 1]。出栈时要判断栈是否为空:

int IsEpSeqStack(seqstack_t *p)
{
    return p->top == -1;
}

获取栈顶数据

int GetTopSeqStack(seqstack_t *p)
{
    if (!IsEpSeqStack(p))
    {
        printf("%d",p->data[p->top]);
        return 0;
    }
    perror("empty");
    return -1;
}

获取栈顶数据时也要判断栈是否为空,栈顶数据即栈针指向的数据。

求栈的长度

int LengthSeqStack(seqstack_t *p)
{
    return p->top + 1;
}

top为最后一个有效元素的下标,故栈的长度为p->top + 1。

清空栈

void ClearSeqStack(seqstack_t *p)
{
    p->top = -1;
}

和顺序表相同,令栈针为-1即可清空顺序栈。

链式栈

结构体

typedef int datatype;
typedef struct linkstack
{
    datatype data;
    struct linkstack *next;
} linkstack_t;

链式栈的结构体和链表的结构体相同,结构体成员都是一个数据域和指针域。

创建空栈

void CreateEpLinkStack(linkstack_t **ptop)
{
    *ptop = NULL;
}

和链表的创建不同,有头链表先要开辟出一个结构体类型大小的空间来存放头节点,而链式栈相当于无头链表,每个节点的数据域都有效,所以创建栈时只需初始化栈针top,注意栈针是在主函数定义的,需要传入子函数进行修改时要传入栈针的地址(二级指针)。

入栈

int PushLinkStack(linkstack_t **ptop, datatype data)
{
    linkstack_t *pnew = (linkstack_t *)malloc(sizeof(linkstack_t));
    if (pnew == NULL)
    {
        perror("push malloc error");
        return -1;
    }
    pnew->data = data;
    pnew->next = *ptop;
    *ptop = pnew;
    return 0;
}

入栈时首先要开辟一个结构体类型大小的空间,然后将要入栈的数据赋给该结构体的数据域。而想要用单向链表实现栈的功能(先入后出,后入先出),那必须每次入栈的节点为头节点,即链表的方向是从栈顶指向栈底。在入栈新节点之前,栈针是指向入栈位置的一位,所以新入栈的节点的指针域要指向当前栈顶节点(pnew->next = *ptop),然后移动栈针指向新节点即可。

出栈

datatype PopLinkStack(linkstack_t **ptop)
{
    if (IsEpLinkStack(*ptop))
    {
        perror("empty");
        return -1;
    }
    datatype temp = (*ptop)->data;
    linkstack_t *pdel = *ptop;
    *ptop = (*ptop)->next;
    free(pdel);
    return temp;
}

先定义一个临时变量temp保存需要出栈的数据,再定义一个结构体类型的指针pdel指向要出栈的节点,将栈针向栈底移动一位,最后将出栈节点free并返回数据temp,当然链式栈的出栈也要判断栈是否为空:

int IsEpLinkStack(linkstack_t *top)
{
    return top == NULL;
}

栈针为空时栈为空。

获取栈顶数据

datatype GetTopLinkStack(linkstack_t *top)
{
    if (!IsEpLinkStack(top))
        return top->data;
    else
    {
        perror("empty");
        return -1;
    }
}

如果栈不为空,就返回栈针指向节点的数据域即是栈顶数据。

求栈的长度

int LengthLinkStack(linkstack_t *top)
{
    int len = 0;
    while (top != NULL)
    {
        len++;
        top = top->next;
    }
    return len;
}

相当于遍历无头链表。

清空栈

void ClearLinkStack(linkstack_t **ptop)
{
    while (!IsEpLinkStack(*ptop))
        PopLinkStack(ptop);
}

只要栈不为空,就一直调用出栈函数,直至栈被清空。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇