C语言--栈与队列2(链栈与二级指针)

一、知识准备

1)c语言结构体指针元素不能赋值,C语言结构体指针必须被结构体变量赋地址或malloc后才能正常使用,不能单独赋值?..._蓝星神的博客-CSDN博客

2)二级指针的作用详解_码农在新加坡的博客-CSDN博客_二级指针

二、链栈的操作函数

0)链栈的定义和一些宏定义

#define ElementType  char//如果要修改数据域类型,修改这里的宏定义,入栈出栈函数的printf,显示栈的printf,主函数的scanf和printf
#define LEN  sizeof(LinkStackNode)
int flag=0;//由于链栈的初始化会出现一个结点并且数据域没有赋值,所以定义一个全局变量辅助第一次入栈,即只赋值但是不开辟新节点,在销毁链栈时再让flag=0
//链栈的结构是首地址没有数据域赋值,上面结点指向下面结点
typedef struct LinkStackNode{
    ElementType Data;
    struct LinkStackNode* Next;
}LinkStackNode,*LinkStackPointer;//第一个参数指链栈结点只是单纯的给宏定义LEN用的,第二个是指指向链栈的指针变量

1)初始化链栈---明确这里的链栈结构首结点的数据域是有赋值的,这样方便操作

//初始化链栈,传入的是一级指针的地址,因为要修改指针变量的值,所以要用地址传递,也就是二级指针修改一级指针的值
void Init_LinkStack(LinkStackPointer* Top){
    (*Top)=(LinkStackPointer)malloc(LEN);
    if((*Top)==NULL){
        printf("初始化链栈失败!\n\n");
        exit(0);
    }
    else{
        printf("初始化链栈成功!\n\n");
        (*Top)->Next=NULL;
    }
}

2)判断链栈是否为空

//判断是否为空链栈,只需传入指向链栈首地址的指针变量即可
int LinkStack_Empty(LinkStackPointer Top){
    if(Top==NULL){
        return 0;
    }
    else    return 1;
}

3)计算链栈元素个数

//计算链栈元素个数,只需传入一级指针即可
int LinkStack_Length(LinkStackPointer Top){
    LinkStackPointer Temp=Top;
    int length=0;
    while(Top!=NULL){
        length++;
        Top=Top->Next;
    }
    Top=Temp; 
    return length;
}

4)入栈---基本不出现溢出现象

//入栈,使用二级指针,因为要修改指向链栈头节点地址的指针变量的值
void Push_LinkStack(LinkStackPointer* Top,ElementType data){
    //因为初始化的时候开辟的结点没有赋值,为了后续操作方便在这里先赋值,下一次再开辟
    if(flag==0){//为了确保销毁链栈后还要入栈的操作
        (*Top)->Data=data;
        flag=1;
        printf("%c元素入栈成功!\n",(*Top)->Data);
    }
    else{
        LinkStackPointer Temp=(LinkStackPointer)malloc(LEN);
        if(Temp==NULL){
            printf("申请内存失败!\n");
        }
        else{
            Temp->Data=data;
            Temp->Next=(*Top);
            (*Top)=Temp;
            printf("%c元素入栈成功!\n",(*Top)->Data);     
        }
    }   
}

5)出栈---时时刻刻判断是否为空

//出栈,使用二级指针,因为要修改指向链栈头节点地址的指针变量的值
void Pop_LinkStack(LinkStackPointer* Top,ElementType* data){
    LinkStackPointer Temp;
    if((*Top)==NULL){
        printf("出栈失败,链栈已空!\n");
    }
    else{
        Temp=(*Top)->Next;
        *data=(*Top)->Data;
        free(*Top);
        (*Top)=Temp;
        printf("%c元素已弹出!\n",*data);
    }
}

6)销毁链栈

//销毁链栈,使用二级指针,因为每次释放一个结点指向链栈头结点地址的指针变量的值要改变,最终指针变量的值为0
void Destroy_LinkStack(LinkStackPointer* Top){
    LinkStackPointer Temp;
    while((*Top)!=NULL){
        Temp=(*Top)->Next;
        free(*Top);
        (*Top)=Temp;
    }
    printf("\n销毁链栈成功!\n");
    flag=0;
}

7)显示链栈

//显示链栈,一级指针
void Show_LinkStack(LinkStackPointer Top){
    LinkStackPointer Temp=Top;
    int i=1;
    if(Top==NULL){
        printf("链栈为空,无法显示!\n");
    }
    else{
        do{
            printf("第%d个结点的元素是%c\n",i++,Temp->Data);
            Temp=Temp->Next;
        }while(Temp!=NULL);
    }
}

三、实践

#include 
#include 
#define ElementType  char//如果要修改数据域类型,修改这里的宏定义,入栈出栈函数的printf,显示栈的printf,主函数的scanf和printf
#define LEN  sizeof(LinkStackNode)
int flag=0;//由于链栈的初始化会出现一个结点并且数据域没有赋值,所以定义一个全局变量辅助第一次入栈,即只赋值但是不开辟新节点,在销毁链栈时再让flag=0
//链栈的结构是首地址没有数据域赋值,上面结点指向下面结点
typedef struct LinkStackNode{
    ElementType Data;
    struct LinkStackNode* Next;
}LinkStackNode,*LinkStackPointer;//第一个参数指链栈结点只是单纯的给宏定义LEN用的,第二个是指指向链栈的指针变量
//初始化链栈,传入的是一级指针的地址,因为要修改指针变量的值,所以要用地址传递,也就是二级指针修改一级指针的值
void Init_LinkStack(LinkStackPointer* Top){
    (*Top)=(LinkStackPointer)malloc(LEN);
    if((*Top)==NULL){
        printf("初始化链栈失败!\n\n");
        exit(0);
    }
    else{
        printf("初始化链栈成功!\n\n");
        (*Top)->Next=NULL;
    }
}
//判断是否为空链栈,只需传入指向链栈首地址的指针变量即可
int LinkStack_Empty(LinkStackPointer Top){
    if(Top==NULL){
        return 0;
    }
    else    return 1;
}
//计算链栈元素个数,只需传入一级指针即可
int LinkStack_Length(LinkStackPointer Top){
    LinkStackPointer Temp=Top;
    int length=0;
    while(Top!=NULL){
        length++;
        Top=Top->Next;
    }
    Top=Temp; 
    return length;
}
//入栈,使用二级指针,因为要修改指向链栈头节点地址的指针变量的值
void Push_LinkStack(LinkStackPointer* Top,ElementType data){
    //因为初始化的时候开辟的结点没有赋值,为了后续操作方便在这里先赋值,下一次再开辟
    if(flag==0){//为了确保销毁链栈后还要入栈的操作
        (*Top)->Data=data;
        flag=1;
        printf("%c元素入栈成功!\n",(*Top)->Data);
    }
    else{
        LinkStackPointer Temp=(LinkStackPointer)malloc(LEN);
        if(Temp==NULL){
            printf("申请内存失败!\n");
        }
        else{
            Temp->Data=data;
            Temp->Next=(*Top);
            (*Top)=Temp;
            printf("%c元素入栈成功!\n",(*Top)->Data);     
        }
    }   
}
//出栈,使用二级指针,因为要修改指向链栈头节点地址的指针变量的值
void Pop_LinkStack(LinkStackPointer* Top,ElementType* data){
    LinkStackPointer Temp;
    if((*Top)==NULL){
        printf("出栈失败,链栈已空!\n");
    }
    else{
        Temp=(*Top)->Next;
        *data=(*Top)->Data;
        free(*Top);
        (*Top)=Temp;
        printf("%c元素已弹出!\n",*data);
    }
}
//销毁链栈,使用二级指针,因为每次释放一个结点指向链栈头结点地址的指针变量的值要改变,最终指针变量的值为0,所以每次销毁栈后还要入栈必须先初始化
void Destroy_LinkStack(LinkStackPointer* Top){
    LinkStackPointer Temp;
    while((*Top)!=NULL){
        Temp=(*Top)->Next;
        free(*Top);
        (*Top)=Temp;
    }
    printf("\n销毁链栈成功!\n");
    flag=0;
}
//显示链栈,一级指针
void Show_LinkStack(LinkStackPointer Top){
    LinkStackPointer Temp=Top;
    int i=1;
    if(Top==NULL){
        printf("链栈为空,无法显示!\n");
    }
    else{
        do{
            printf("第%d个结点的元素是%c\n",i++,Temp->Data);
            Temp=Temp->Next;
        }while(Temp!=NULL);
    }
}
int main(){
    //变量定义
    LinkStackPointer Top;
    ElementType c;
    printf("注意:销毁链栈后再次入栈必须进行初始化,否则会出错!\n\n");
    //初始化链栈,传入二级指针
    Init_LinkStack(&Top);
    //链栈的简单入栈
    Push_LinkStack(&Top,'c');
    Push_LinkStack(&Top,'b');
    Push_LinkStack(&Top,'a');
    //判断此时是否入栈正确
    printf("\n链栈有%d个元素\n",LinkStack_Length(Top));
    //显示一下链栈的内容
    printf("\n");
    Show_LinkStack(Top);
    printf("\n");
    //链栈2次出栈
    Pop_LinkStack(&Top,&c);
    Pop_LinkStack(&Top,&c);
    //判断此时是否出栈正常
    printf("\n链栈有%d个元素\n",LinkStack_Length(Top));
    //销毁链栈
    Destroy_LinkStack(&Top);
    //判断此时销毁是否正常
    printf("\n链栈有%d个元素\n",LinkStack_Length(Top));
    //判断显示链栈这个函数是否正常
    Show_LinkStack(Top);
    //销毁后入栈必须初始化
    printf("\n");
    Init_LinkStack(&Top);
    printf("\n");
    //销毁后再次入栈实验
    Push_LinkStack(&Top,'x');
    Push_LinkStack(&Top,'w');
    Push_LinkStack(&Top,'e');
    //判断再次入栈是否正确
    printf("\n链栈有%d个元素\n",LinkStack_Length(Top));
    //销毁后显示栈内容
    printf("\n");
    Show_LinkStack(Top);
    printf("\n");
    return 0;
}

你可能感兴趣的:(C语言--栈与队列,c语言,开发语言)