1.栈的特点 

    先进后出或者说后进先出。

2.基于顺序表实现栈的相关操作

2.1 头文件seqstack.h

//头文件只被编译一次
#pragma once
//宏定义一个标识符,用于打印函数名
#define HEADER printf("==================%s==================\n",__FUNCTION__);
//定义栈中元素的数据类型
typedef char SeqStackType;
//顺序表实现栈时定义结构体
typedef struct SeqStack
{
    //用于存放栈的元素,之所以定义为指针类型而不是指定大小的数组类型,是为了方便动态开辟内存
    SeqStackType* data;
    //用来表示栈的有效元素个数
    size_t size;
    //用来表示栈首次申请的空间的最大长度
    size_t capacity;
}SeqStack;
/*=========函数声明========*/
//1.初始化
void SeqStackInit(SeqStack* stack);
//2.销毁
void SeqStackDestroy(SeqStack* stack);
//3.打印
void SeqStackPrintChar(SeqStack* stack,char* msg);
//4.入栈
void SeqStackPush(SeqStack* stack,SeqStackType value);
//5.扩容
SeqStackType* SeqStackResize(SeqStack* stack);
//6.出栈
int SeqStackPop(SeqStack* stack);
//7.取栈顶元素 
int SeqStackTop(SeqStack* stack,SeqStackType* value);

2.2 初始化

//思路:将有效元素个数size初始化为0,动态开辟内存的最大长度capacity设一个指定值1000,动态开辟data内存空间

void SeqStackInit(SeqStack* stack)
{
    //非法输入
    if(stack==NULL)
        return;
    //初始化有效元素个数为0
    stack->size=0;
    //初始化动态开辟内存的最大长度为1000
    stack->capacity=1000;
    //动态开辟空间
    stack->data=(SeqStackType*)malloc((stack->capacity)*sizeof(SeqStackType));
}

2.3 销毁

//思路:将有效元素个数size置为0,动态开辟内存的最大长度capacity置为0,释放动态开辟的内存data

void SeqStackDestroy(SeqStack* stack)
{
    //非法输入
    if(stack==NULL)
        return;
    //将栈中有效元素个数置为0
    stack->size=0;
    //将最大长度置为0
    stack->capacity=0;
    //释放动态开辟的内存data
    free(stack->data);
}

2.4 入栈

//思路:分为两种情况:1.初始化动态开辟的内存空间已满时需要扩容再入栈 2.初始化动态开辟的内存未满时,直接入栈

void SeqStackPush(SeqStack* stack,SeqStackType value)
{
    //非法输入
    if(stack==NULL)
        return;
    //判断栈是否已满
    if(stack->size>=stack->capacity)
    {
        //扩容
        stack->data=SeqStackResize(stack);
    }
    //入栈操作
    stack->data[stack->size]=value;
    stack->size++;

}

//扩容

//思路:1.将stack->capacity设置的更大一点2.开辟新的空间3.将原有数据搬运到新的内存空间

SeqStackType* SeqStackResize(SeqStack* stack)
{
    //非法输入
    if(stack==NULL)
        return NULL;
    //判断是否已满
    if(stack->size<stack->capacity)
        return stack->data;
    //已满时,进行扩容
    stack->capacity=2*(stack->capacity)+1;
    //开辟新的空间
    SeqStackType* new_stack=(SeqStackType*)malloc((stack->capacity)*sizeof(SeqStackType));
    //将原有数据进行搬运
    size_t i=0;
    for(i=0;i<stack->size;i++)
    {
        new_stack[i]=stack->data[i];
    }
    //释放旧内存空间
    free(stack->data);
    //返回新开辟的空间位置
    return new_stack;
}

2.5 出栈

//思路:将有效元素个数减1即可

int SeqStackPop(SeqStack* stack)
{
    //非法输入
    if(stack==NULL)
        return 0;  //返回0表示出栈失败
    //空栈时无法出栈
    if(stack->size==0)
        return 0;
    stack->size--;
    //出栈成功返回1
    return 1;
}

2.6 取栈顶元素

//思路:让该函数返回两个有效信息:1.是否可以出栈,该参数作为返回参数2.出栈的元素,该参数作为输出参数返回

int SeqStackTop(SeqStack* stack,SeqStackType* value)
{
    //非法输入
    if(stack==NULL||value==NULL)
        return 0;  //返回0表示出栈失败
    //空栈
    if(stack->size==0)
        return 0;
    //取栈顶元素
    *value=stack->data[stack->size-1];
    return 1;   //返回1表示出栈成功
}

2.7 测试代码是否正确

为了测试代码的方便需要写打印栈中元素的函数

//思路:进行遍历栈去打印,两个参数:1.用于接收栈的地址 2.用于打印一行字符串

void SeqStackPrintChar(SeqStack* stack,char* msg)
{
    //非法输入
    if(stack==NULL||msg==NULL)
        return;
    //打印字符串
    printf("%s\n",msg);
    //遍历打印栈中元素
    size_t i=0;
    for(i=0;i<stack->size;i++)
    {
        printf("%c ",stack->data[i]);
    }
    printf("\n");

}

//1.测试SeqStackInit

void Test_SeqStackInit()
{
    HEADER;
    SeqStack stack;
    SeqStackInit(&stack);
    printf("stack.size expected 0,actual %d\n",stack.size);
    printf("stack.capacity expected 1000,actual %d\n",stack.capacity);

}

//2.测试SeqStackDestroy

void Test_SeqStackDestroy()
{
    HEADER;
    SeqStack stack;
    SeqStackInit(&stack);
    SeqStackDestroy(&stack);
    printf("stack.size expected 0,actual %d\n",stack.size);
    printf("stack.capacity expected 0,actual %d\n",stack.capacity);

}

//3.测试SeqStackPush

void Test_SeqStackPush()
{
    HEADER;
    SeqStack stack;
    SeqStackInit(&stack);
    SeqStackPush(&stack,'a');
    SeqStackPush(&stack,'b');
    SeqStackPush(&stack,'c');
    SeqStackPrintChar(&stack,"入栈'a''b''c'");

}

//4.测试SeqStackPop

void Test_SeqStackPop()
{
    HEADER;
    SeqStack stack;
    SeqStackInit(&stack);
    SeqStackPush(&stack,'a');
    SeqStackPush(&stack,'b');
    SeqStackPush(&stack,'c');
    int ret=SeqStackPop(&stack);
    SeqStackPrintChar(&stack,"出栈一个元素");
    printf("expected 1,actual %d\n",ret);
    ret=SeqStackPop(&stack);
    SeqStackPrintChar(&stack,"出栈两个元素");
    printf("expected 1,actual %d\n",ret);
    ret=SeqStackPop(&stack);
    SeqStackPrintChar(&stack,"出栈三个元素");
    printf("expected 1,actual %d\n",ret);
    ret=SeqStackPop(&stack);
    SeqStackPrintChar(&stack,"尝试对空栈出栈");
    printf("expected 0,actual %d\n",ret);

}

//5.测试SeqStackTop

void Test_SeqStackTop()
{
    HEADER;
    SeqStack stack;
    SeqStackType value;
    SeqStackInit(&stack);
    SeqStackPush(&stack,'a');
    SeqStackPush(&stack,'b');
    SeqStackPush(&stack,'c');
    size_t ret=SeqStackTop(&stack,&value);
    SeqStackPrintChar(&stack,"取栈顶元素");
    printf("expected 1,actual %d\n",ret);
    printf("expected 'c',actual %c\n",value);
    SeqStackPop(&stack);
    ret=SeqStackTop(&stack,&value);
    SeqStackPrintChar(&stack,"出栈一次后再取栈顶元素");
    printf("expected 1,actual %d\n",ret);
    printf("expected 'b',actual %c\n",value);
    SeqStackPop(&stack);
    SeqStackPop(&stack);
    ret=SeqStackTop(&stack,&value);
    SeqStackPrintChar(&stack,"出栈三次后尝试对空栈取栈顶元素");
    printf("expected 0,actual %d\n",ret);

}

//主函数

int main()
{
    Test_SeqStackInit();
    Test_SeqStackDestroy();
    Test_SeqStackPush();
    Test_SeqStackPop();
    Test_SeqStackTop();
    return 0;

}

3.基于链表实现栈的相关操作

3.1 头文件linkstack.h

//头文件只被编译一次
#pragma once
//宏定义一个标识符,用于打印函数名
#define HEADER printf("==============%s============\n",__FUNCTION__);
//为了方便用户修改其节点元素的数据类型,将其进行宏定义
#define LinkStackType char
//定义链表实现栈的结构体
typedef struct LinkStack
{
    //存放链表元素
    LinkStackType data;
    //存放下一节点的地址
    struct LinkStack* next;
}LinkStack;

3.2 初始化

//思路:将头指针的指向置为空即可

void LinkStackInit(LinkStack** pstack)
{
    //非法输入
    if(pstack==NULL)
        return;
    //修改*pstack的指向
    *pstack=NULL;

3.3 销毁

//思路:遍历栈去销毁每一个节点

void LinkStackDestroy(LinkStack** pstack)
{
    //非法输入
    if(pstack==NULL)
        return;
    //空栈时,无需销毁
    if(*pstack==NULL)
        return;
    //遍历栈
    LinkStack* cur=*pstack;
    while(cur!=NULL)
    {
        LinkStack* to_delete=cur;
        cur=cur->next;
        free(to_delete);
    }
    //将*pstack的指向置为空
    *pstack=NULL;

}

3.4 入栈

//思路:头插实现入栈,新建节点并修改头指针的指向

void LinkStackPush(LinkStack** pstack,LinkStackType value)
{
    //非法输入
    if(pstack==NULL)
        return;
    //创建新节点
    LinkStack* new_node=(LinkStack*)malloc(sizeof(LinkStack));
    new_node->data=value;
    new_node->next=NULL;
    //修改*pstack的指向
    new_node->next=*pstack;
    *pstack=new_node;

}

3.5 出栈

//思路:头删实现出栈,第一个节点位置就是要出栈的节点,修改头指针的指向

int LinkStackPop(LinkStack** pstack)
{
    //非法输入
    if(pstack==NULL)
        return 0;  //返回0表示出栈失败
    //空栈时,无法出栈
    if(*pstack==NULL)
        return 0;
    //找到第一个节点
    LinkStack* to_delete=*pstack;
    //修改头指针的指向
    *pstack=to_delete->next;
    //销毁要出栈的节点
    free(to_delete);
    //出栈成功返回1
    return 1;

}

3.6 取栈顶元素

//思路:由于是头插实现入栈,所以只需找到第一个节点即可,返回两个有效信息:1.取栈顶元素是否成功2.栈顶元素的值

int LinkStackTop(LinkStack* stack,LinkStackType* value)
{
    //空栈时,取栈顶元素失败
    if(stack==NULL)
        return 0;   //返回0表示取栈顶元素失败
    //取栈顶元素
    *value=stack->data;
    //取栈顶元素成功返回1
    return 1;

}

3.7 测试代码是否正确

//为了测试代码的方便需要写打印栈中元素的函数

//思路:遍历栈去打印每一个节点

void LinkStackPrintChar(LinkStack* stack)
{
    //由于是头插实现入栈,所以需要逆序打印元素
    if(stack==NULL)
        return;
    LinkStackPrintChar(stack->next);
    printf("[%p][%c] ",stack,stack->data);

}

//1.测试LinkStackPush

void Test_LinkStackPush()
{
    HEADER;
    LinkStack* stack;
    LinkStackInit(&stack);
    LinkStackPush(&stack,'a');
    LinkStackPush(&stack,'b');
    LinkStackPush(&stack,'c');
    printf("入栈'a''b''c'\n");
    LinkStackPrintChar(stack);
    printf("\n");

}

//2.测试LinkStackPop

void Test_LinkStackPop()
{
    HEADER;
    LinkStack* stack;
    LinkStackInit(&stack);
    LinkStackPush(&stack,'a');
    LinkStackPush(&stack,'b');
    LinkStackPush(&stack,'c');
    printf("入栈'a''b''c'\n");
    LinkStackPrintChar(stack);
    printf("\n");
    int ret=LinkStackPop(&stack);
    printf("出栈一次\n");
    printf("excepted 1,actual %d\n",ret);
    LinkStackPrintChar(stack);
    printf("\n");
    LinkStackPop(&stack);
    ret=LinkStackPop(&stack);
    printf("出栈三次\n");
    printf("excepted 1,actual %d\n",ret);
    LinkStackPrintChar(stack);
    printf("\n");
    ret=LinkStackPop(&stack);
    printf("尝试对空栈出栈\n");
    printf("excepted 0,actual %d\n",ret);
    LinkStackPrintChar(stack);
    printf("\n");

}

//3.测试LinkStackTop

void Test_LinkStackTop()
{
    HEADER;
    LinkStack* stack;
    LinkStackType value;
    LinkStackInit(&stack);
    LinkStackPush(&stack,'a');
    LinkStackPush(&stack,'b');
    LinkStackPush(&stack,'c');
    int ret=LinkStackTop(stack,&value);
    printf("ecpected 1,actual %d\n",ret);
    printf("ecpected 'c',actual %c\n",value);
    LinkStackPop(&stack);
    ret=LinkStackTop(stack,&value);
    printf("ecpected 1,actual %d\n",ret);
    printf("ecpected 'b',actual %c\n",value);
    LinkStackPop(&stack);
    LinkStackPop(&stack);
    ret=LinkStackTop(stack,&value);
    printf("ecpected 0,actual %d\n",ret);

}

//主函数

int main()
{
    Test_LinkStackPush();
    Test_LinkStackPop();
    Test_LinkStackTop();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值