数据结构之栈(链栈)的基本操作

一、关于链栈的操作,它和链表有很大的相似之处,不同的是,栈只允许在栈顶进行入栈操作,和链表的头插法相同。

二、之所以要用链栈,是因为如果我们用顺序栈的话,需要提前申请一片内存空间,但是如果我们值存入少量的元素,那么这片内存空间难免会造成一定的浪费。如果使用链栈的话,我们只在入栈的时候进行内存的申请,然后再进行元素的存储,既可以进行动态的内存申请。根据实际入栈元素的多少申请所需的空间即可。

三、链栈和顺序栈的基本操作都是一样的,包括:初始化,求长度,判断栈是否为空,入栈,出栈,取栈顶元素。

(1)先定义一个结构体,这个结构体中,包括栈中每个节点的节点值data,和指向下一个栈节点的指针next

#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
//定义一个结构体栈
typedef struct StackNode
{
    ElemType data;
    struct StackNode *next;
}StackList;
typedef StackList *LStack;//声明一个指向这个结构体的指针类型Lstack

(2)进行初始化,将链栈的顶处设置一个指针,用来指向这个栈,这个指针内不存储东西,那么刚开始就把这个栈顶指针设置为NULL即可。

//初始化链栈
void Init(LStack *s)
{
    (*s)=(LStack)malloc(sizeof(StackList));
    (*s)->next=NULL;
}

(3)判断栈是否为空,只需要判断栈顶指针的指针域是否为空即可。为空返回0,不为空返回1。

//判断栈是否为空
int Empty(LStack s)
{
    if(s->next==NULL)
    {
        return 0;//为空返回0,
    }
    return 1;    //不为空返回1,
}

(4)求栈的长度,即从栈顶的下一个,也就是第一个元素开始,往下遍历,一直遍历到指针指向空,说明遍历完了,没遍历一个,就计数器加一,临时的指针变量往后移动一位p=p->next

//求栈中的元素数量,即长度
int Printf(LStack s)
{
    int count=0;
    LStack p;
    p=s->next;//指向第一个元素
    while(p){
        count++;
        p=p->next;
    }
    return count;
}

(5)入栈,将值x,压入到栈中,我们首先声明一个指针变量,来存储这个元素值x,当然,因为我们要用这个指针变量存储东西,所以我们要先为这个指针变量申请内存空间malloc,然后存入。

//入栈
void Push(LStack *s,ElemType x)
{
    LStack p;//声明一个指针变量
    p=(LStack)malloc(sizeof(StackList));//为这个指针变量分配空间
    p->data=x;        //将入站的元素值存入到这个指针的数据域
    p->next=(*s)->next;  //这两个步骤和顺序链表的操作相似。
    (*s)->next=p;
}

(6)出栈,首先要判断栈是否为空,如果不为空,我们指针p指向栈中的第一个节点,然后用e记录下当前栈顶元素的值,接着将不存东西的栈顶指针的指针域指向指针p的下一个节点处,释放指针p即可。

//出栈
ElemType Pop(LStack *s)
{
    LStack p;//声明一个结构体类型的指针变量
    ElemType e;
    p=(*s)->next;//指向栈中的栈顶元素
    if(p==NULL)
    {
        return 0;
    }
    (*s)->next=p->next;//不为空的话就让栈顶元素变成当前栈顶p的下一个
    e=p->data;//存放以下删除的栈顶元素
    free(p);  //释放指针
    return e; //返回删除的栈顶指针的值
}

(7)获取栈顶元素的值,首先要判断栈是否为空,如果不为空,直接返回栈中的第一个节点的值即可

//取栈顶元素的值
ElemType GetTop(LStack s)
{
    if(Empty(s)){//如果栈顶元素不为空的话,则打印出栈顶元素
        return s->next->data;
    }
    return 0;
}

(8)主函数,对上面定义的各个函数进行定义,这一模块的代码块,大家可以根据自己的需求自己进行定义即可,我只给出我所写的一部分

int main()
{
    LStack s;
    int x;
    ElemType e;
    //初始化栈
    Init(&s);
    //判断栈是否为空
    x=Empty(s);
    if(x)
    {
        printf("栈空\n");
    }
    //扫描要入站的元素
    Push(&s,5);
    Push(&s,4);
    Push(&s,6);
    Push(&s,8);
    Push(&s,2);
    //获取栈的长度
    x=Printf(s);
    printf("栈的长度为%d\n",x);
    //获取当前栈的栈顶元素
    e=GetTop(s);
    if(e){//如果栈不为空的话输出
        printf("当前栈顶元素为:%d\n",e);
    }
    //删除当前栈的栈顶元素
    e=Pop(&s);
    if(x)//如果栈不为空的话进行出栈操作
    {
        printf("删除的元素为:%d\n",e);
    }
    //获取当前的栈顶元素
    e=GetTop(s);
    if(e){//如果栈不为空的话输出
        printf("当前栈顶元素为:%d\n",e);
    }
    x=Printf(s);
    printf("栈的长度为%d\n",x);
    return 0;
}

(9)我这个案例的运行结果为:

总结:有一些人在定义一个结构体的指针时,当把它传入到另外一个函数中时,不知道该如何编写,如果你在定义的时候,这个结构体的类型不是一个指针,那么你如果在主函数中定义一个结构体指针变量,传入到其他函数时,要使用双重指针**,才能进行栈的更改,我在这里刚开始就定义了一个指向结构体的指针类型,那我在声明一个结构体类型的指针时,就不需要加*,原理是一样的。如有错误,请大佬留言,如果有更好的方法,欢迎交流。

猜你喜欢

转载自blog.csdn.net/BaoITcore/article/details/121257979
今日推荐