C语言实现栈(基于链表)

栈的底层数据结构可以是数组,也可以是链表,用链表实现栈,理论上是无限大的

下面是链栈的实现代码

#include
#include
typedef int datatype;

//Link Stack 实现顺序栈,使用链表来实现

// struct LinkList
// {
//     datatype data;
//     struct LinkList *next;
// };

struct stack
{
    datatype data;
    struct stack *next;
};

typedef struct stack Stack;
//创建栈
Stack *s;
//初始化栈
void init()
{
    s=NULL;
}

//判断栈是否为空
bool Empty()
{
    if(s==NULL)
    {
        return true;
    }
    else
    {
        return false;
    }
}

//判断栈是否已满了
// void full(Stack *s)
// {
//     if(s->top==realsize-1)
//     {
//         realsize++;
//         s->data=(datatype *)realloc(s->data,realsize);
//     }
// }

//入栈
void Push(datatype element)
{
    Stack *p = (Stack *)malloc(sizeof(Stack));
    p->data=element;
    p->next=s;
    s=p;             
}

//出栈
void Pop()
{
    if(!Empty(s))
    {
        s=s->next;
    }
    else
    {
        printf("栈空\n");
    }
}

//取栈顶元素
datatype Top()
{
    if(!Empty(s))
    {
        return s->data;
    }
    else
    {
        printf("栈空\n");
    }
}

//销毁栈
void Destroy()
{
    free(s);//因该销毁每一个元素
    s=NULL;
    // free(s.data); //容易导致失败
}

测试代码

#include
#include "LinkStack.h"
int main()
{
    int i=0;
    // struct stack s;
    //初始化栈
    printf("\n###########初始化栈###########\n");
    init();
    printf("----------------------------------");    
    //入栈操作
    printf("\n###########入栈操作###########\n");
    for(i=0;i<=10;i++)
    {
        Push(i);
    }
    printf("----------------------------------");
    printf("\n###########取栈顶元素###########\n");
    printf("%d\n",Top());
    printf("----------------------------------");    
    //出栈操作
    printf("\n###########出栈操作###########\n");
    for(i=0;i<=12;i++)
    {
        Pop();
    }  
    printf("----------------------------------");    
    printf("\n###########取栈顶元素###########\n");
    Top();
    printf("----------------------------------");
    printf("\n###########销毁栈############\n"); 
    Push(10);
    Destroy();
    Top();
}


这样的栈和之前数组实现的栈有共同的缺点,无法自己定义多个栈,但是全局变量避免了一个容易出错的地方,下面会说到

这里要实现和前一篇数组实现栈的自己定义多个栈,如果套用之前的方法,就会出现一个错误,数组是直接把栈作为参数传入函数,对栈的修改,就会改变原来栈的元素值。

但是这里链栈,把指针作为参数传入函数,修改参数指针指向,并不会,改变原来的指针

有两种方法可以实现,一种是将指针作为函数值返回,另一种是使用二级指针

先看第一种方法的栈的实现

#include
#include
// #define maxsize 10
typedef int datatype;

//Link Stack 实现顺序栈,使用链表来实现

// struct LinkList
// {
//     datatype data;
//     struct LinkList *next;
// };

struct stack
{
    datatype data;
    struct stack *next;
};

typedef struct stack Stack;

// Stack *s;
//初始化栈
Stack* init(Stack *s)
{
    s=NULL;
    return s;
}

//判断栈是否为空
bool Empty(Stack *s)
{
    if(s==NULL)
    {
        return true;
    }
    else
    {
        return false;
    }
}

//判断栈是否已满了
// void full(Stack *s)
// {
//     if(s->top==realsize-1)
//     {
//         realsize++;
//         s->data=(datatype *)realloc(s->data,realsize);
//     }
// }

//入栈
Stack* Push(Stack *s,datatype element)
{
    Stack *p = (Stack *)malloc(sizeof(Stack));
    p->data=element;
    p->next=s;
    s=p;             //这里指针只是副本,无法修改原来的指针,要么使用二级指针,要么返回这个指针
    return s;
}

//出栈
Stack* Pop(Stack *s)
{
    if(!Empty(s))
    {
        s=s->next;
    }
    else
    {
        printf("栈空\n");
    }
    return s;
}

//取栈顶元素
datatype Top(Stack *s)
{
    if(!Empty(s))
    {
        return s->data;
    }
    else
    {
        printf("栈空\n");
    }
}

//销毁栈
Stack* Destroy(Stack *s)
{
    free(s);//因该销毁每一个元素
    s=NULL;
    return s;
    // free(s.data); //容易导致失败
}


栈的测试代码

#include
#include "LinkStack1.0.h"
int main()
{
    int i=0;
    Stack p; 
    Stack *s;
    s=&p;
    // struct stack s;
    //初始化栈
    printf("\n###########初始化栈###########\n");
    s=init(s);
    printf("----------------------------------");    
    //入栈操作
    printf("\n###########入栈操作###########\n");
    for(i=0;i<=10;i++)
    {
        s=Push(s,i);
    }
    printf("----------------------------------");
    //取栈顶元素
    printf("\n###########取栈顶元素###########\n");
    printf("%d\n",Top(s));
    printf("----------------------------------");    
    //出栈操作
    printf("\n###########出栈操作###########\n");
    for(i=0;i<=12;i++)
    {
        s=Pop(s);
    }  
    printf("----------------------------------");
    //取栈顶元素    
    printf("\n###########取栈顶元素###########\n");
    Top(s);
    printf("----------------------------------");
    //销毁栈
    printf("\n###########销毁栈###########\n"); 
    s=Push(s,10);
    s=Destroy(s);
    Top(s);
}


这种办法比较麻烦,增加了使用者的负担,增加了代码量

再看第二种方法,二级指针(指针的指针)栈的实现

#include
#include
// #define maxsize 10
typedef int datatype;

//Link Stack 实现顺序栈,使用链表来实现

struct LinkList
{
    datatype data;
    struct LinkList *next;
};

typedef struct stack* Stack;

//初始化栈
void init(Stack *s)
{
    *s=NULL;

}

//判断栈是否为空
bool Empty(Stack *s)
{
    if(*s==NULL)
    {
        return true;
    }
    else
    {
        return false;
    }
}

//判断栈是否已满了
// void full(Stack *s)
// {
//     if(s->top==realsize-1)
//     {
//         realsize++;
//         s->data=(datatype *)realloc(s->data,realsize);
//     }
// }

//入栈
void Push(Stack *s,datatype element)
{
    Stack *p = (Stack *)malloc(sizeof(struct LinkList));
    p->data=element;
    p->next=*s;
    *s=p;             //这里指针只是副本,无法修改原来的指针,要么使用二级指针,要么返回这个指针
}

//出栈
void Pop(Stack *s)
{
    if(!Empty(s))
    {
        *s=(*s)->next;
    }
    else
    {
        printf("栈空\n");
    }
}

//取栈顶元素
datatype Top(Stack *s)
{
    if(!Empty(s))
    {
        return (*s)->data;
    }
    else
    {
        printf("栈空\n");
    }
}

//销毁栈
void Destroy(Stack *s)
{
    free(s);//因该销毁每一个元素
    *s=NULL;
    // free(s.data); //容易导致失败
}

栈的测试代码

#include
#include "LinkStack2.0.h"
int main()
{
    int i=0;
    Stack p; 
    Stack *s;
    s=&p;
    // struct stack s;
    //初始化栈
    printf("\n###########初始化栈###########\n");
    init(s);
    printf("----------------------------------");    
    //入栈操作
    printf("\n###########入栈操作###########\n");
    for(i=0;i<=10;i++)
    {
        Push(s,i);
    }
    printf("----------------------------------");
    //取栈顶元素
    printf("\n###########取栈顶元素###########\n");
    printf("%d\n",Top(s));
    printf("----------------------------------");    
    //出栈操作
    printf("\n###########出栈操作###########\n");
    for(i=0;i<=12;i++)
    {
        Pop(s);
    }  
    printf("----------------------------------");
    //取栈顶元素    
    printf("\n###########取栈顶元素###########\n");
    Top(s);
    printf("----------------------------------");
    //销毁栈
    printf("\n###########销毁栈###########\n"); 
    Push(s,10);
    Destroy(s);
    Top(s);
}

这样即可实现链栈。这里指针作为参数传递进函数,实际上只是一份拷贝,只是这分拷贝和原来的指针是同一个指向,所以改变指针指向的内容,是可以的,但是改变指针本身是错误的,所以需要二级指针


你可能感兴趣的:(C)