C语言 复杂的栈(链表栈)

//复杂的栈--链表栈
#include<stdio.h>
#include<stdlib.h>


#define datatype int//定义链表栈数据类型
//定义链表栈结构
struct stacklink{
    datatype data;
    struct stacklink *pnext;
};

typedef struct stacklink StackLink;

//判断栈是否为空
int isempty(StackLink *phead);
//进栈
StackLink * push(StackLink *phead, datatype num);
//出栈
StackLink * pop(StackLink *phead, StackLink *pout);
//清空
StackLink * setempty(StackLink *phead);
//遍历栈中的数据
void findall(StackLink *phead);

//链表栈容量无限大,但是代价是增加链表遍历成本

void main(){
    //定义链表栈的头指针
    StackLink * phead = NULL;
    //压栈
    phead = push(phead, 1);
    phead = push(phead, 2);
    phead = push(phead, 3);
    phead = push(phead, 4);
    phead = push(phead, 5);
    //打印栈中的数据
    findall(phead);
    //出栈
    StackLink *pout = (StackLink *)malloc(sizeof(StackLink));
    phead = pop(phead, pout);
    printf("
弹出的元素是%d;
", pout->data);
    free(pout);
    ////全部出栈
    //while (phead!=NULL){
    //    StackLink *pout = malloc(sizeof(StackLink));
    //    phead = pop(phead, pout);
    //    printf("
弹出的元素是%d;
", pout->data);
    //    free(pout);
    //}
    printf("
================================
");
    //打印栈中的数据
    findall(phead);
    printf("
================================
");
    //清空栈内元素
    phead = setempty(phead);
    //打印栈中的数据
    findall(phead);
    system("pause");
}

//判断栈是否为空
int isempty(StackLink *phead){
    if (phead == NULL)
    {
        return 1;
    }
    else{
        return 0;
    }
}

//进栈
StackLink * push(StackLink *phead, datatype num){
    //分配内存空间
    StackLink *p = (StackLink *)malloc(sizeof(StackLink));
    StackLink *p1 = phead;
    p->data = num;
    p->pnext = NULL;
    //判断栈是否为空
    if (isempty(phead))
    {
        //栈为空
        phead = p;
        //注意:这里是给指针副本phead赋值,但是main()函数里phead的值并没有变化
        //要在函数里修改一个指针的值,应该使用二级指针,但是根据代码优化原则,尽量不使用二级指针,
        //因此我们将phead当做返回值返回
    }
    else{
        while (p1->pnext != NULL){
            p1 = p1->pnext;
        }
        p1->pnext = p;
        //这里的phead->pnext会直接影响main()函数里phead的值,因为phead->pnext本质上等于(*phead).pnext
        //修改的是phead指针指向数据的值,而不是修改phead本身
    }
    return phead;
}

//遍历栈中的数据
void findall(StackLink *phead){
    StackLink *p = phead;
    while (p != NULL){
        printf("%d
", p->data);
        p = p->pnext;
    }
}

//出栈
StackLink * pop(StackLink *phead, StackLink *pout){
    if (phead == NULL)//判断栈是否为空
    {
        return NULL;
    }
    else{
        pout->pnext = NULL;
        //不为空
        //出栈,每次弹出最后一个
        //分两种情况
        //1.只有一个元素,只有一个元素,只需要弹出头指针本身
        if (phead->pnext == NULL)
        {
            //pout = phead; 错误,这样只是改变pout指向的地址,而free(phead)会彻底释放phead指向地址的内存
            //结果就是pout也为NULL
            pout->data = phead->data;

            //注意:链表栈删除必须释放内存
            free(phead);
            phead = NULL;
            //这个改变形参phead的值,所以只能返回phead,而有任何地方修改pout的值
            return phead;
        }
        //2.多个元素,找到倒数第二个元素
        else{
            StackLink *p = phead;
            while (phead->pnext->pnext != NULL){
                phead = phead->pnext;
            }
            pout->data = phead->pnext->data;
            //删除栈中最后一个元素
            free(phead->pnext);
            phead->pnext = NULL;
            return p;
        }

    }
}

//清空
StackLink * setempty(StackLink *phead){
    //清空的思路是,1,2,3,4,5通过头指针找到1,将2删除,把3移到2的位置上,再删除3
    //不太清楚循环次数,所以用while
    StackLink *p = NULL;
    while (phead->pnext != NULL){//当第二个元素是NULL的时候,退出循环
        //删除第二个
        //p是第三个的指针
        p = phead->pnext->pnext;
        //开始删除第二个
        free(phead->pnext);
        phead->pnext = p;
    }
    //最后删除第一个元素
    free(phead);
    return NULL;
}

原文地址:https://www.cnblogs.com/zhanggaofeng/p/5230658.html