【数据结构】栈和队列

本文详细介绍了栈和队列的概念、结构以及它们在C语言中的实现,包括初始化、销毁、入栈、出栈、判空、获取栈顶/队头元素、获取栈中/队列元素个数等基本操作。栈遵循后进先出(LIFO)原则,而队列遵循先进先出(FIFO)原则,文中还给出了栈和队列的完整C代码实现。
摘要由CSDN通过智能技术生成

1.栈

1.1栈的概念及结构

栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶
出栈:栈的删除操作叫做出栈。出数据也在栈顶

1.2栈的实现

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的

代价比较小。

首先在VS里面的源文件建立test.cStack.c,在头文件里面建立Stack.h

Stack.h:

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef int STDataType;
typedef struct stack
{
    STDataType* a;
    int top;
    int capacity;
}ST;

1.2.1初始化

Stack.h

void stackInit(ST* ps);//初始化

Stack.c

#include "Stack.h"
void stackInit(ST* ps)
{
    assert(ps);
    ps->a = NULL;
    ps->top = 0;//也可以是ps->top=-1;
    ps->capacity = 0;
}

本文采用top=0

1.2.2 销毁

Stack.h

void stackDestroy(ST* ps);//销毁

Stack.c

void stackDestroy(ST* ps)
{
    assert(ps);
    free(ps->a);
    ps->a = NULL;
    ps->capacity = ps->top = 0;
}

1.2.3 入栈

Stack.h

void stackPush(ST* ps, STDataType x);//入栈

Stack.c

void stackPush(ST* ps, STDataType x)
{
    assert(ps);
    //考虑扩容
    if (ps->top == ps->capacity)
    {
        int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
        ps->a = (STDataType*)relloc(ps->a, sizeof(STDataType)*newCapacity);
        if (ps->a == NULL)
        {
            printf("realloc fail\n");
            exit(-1);
        }
        ps->capacity = newCapacity;//更新容量
    }
    ps->a[ps->top] = x;//将数据压进去
    ps->top++;//栈顶上移
}

test.c

#include "Stack.h"
void TestStack()
{
    ST st;
    stackInit(&st);
    stackPush(&st, 1);
    stackPush(&st, 2);
    stackPush(&st, 3);
}
int main()
{
    TestStack();
    return 0;
}

调试结果:

1.2.4 出栈

Stack.h

void stackPop(ST* ps);//出栈

Stack.c

//出栈之前要确保top不为空,因此需要断言top>0
void stackPop(ST* ps)
{
    assert(ps);
    assert(ps->top > 0);
    ps->top--;
}

test.c

#include "Stack.h"
void TestStack()
{
    ST st;
    stackInit(&st);
    stackPush(&st, 1);
    stackPush(&st, 2);
    stackPush(&st, 3);
    stackPop(&st);
}
int main()
{
    TestStack();
    return 0;
}

调试过程:

1.2.5 判空

Stack.h

bool stackEmpty(ST* ps);//判断是否为空

Stack.c

bool stackEmpty(ST* ps)
{
    assert(ps);
    return ps->top == 0;//如果top为0,那就是为真,直接返回
}

1.2.6 获取栈顶元素

Stack.h

STDataType stackTop(ST* ps);//取栈顶数据

Stack.c

//由于本文采用top=0,先压栈,top再++,因此top-1才是栈顶元素。
STDataType stackTop(ST* ps)
{
    assert(ps);
    assert(ps->top > 0);
    return ps->a[ps->top - 1];//top-1才是栈顶元素
}

1.2.7 获取栈中的有效元素个数

Stack.h

int stackSize(ST* ps);//栈的有效元素个数

Stack.c

//这里需要注意的是,栈顶元素是下标top-1,跟数组一样,总个数是top,而不是top-1
int stackSize(ST* ps)
{
    assert(ps);
    return ps->top;//不是top-1
}

1.3 完整代码展示

Stack.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef int STDataType;
typedef struct stack
{
    STDataType* a;
    int top;
    int capacity;
}ST;
void stackInit(ST* ps);//初始化
void stackDestroy(ST* ps);//销毁
void stackPush(ST* ps, STDataType x);//入栈
void stackPop(ST* ps);//出栈
STDataType stackTop(ST* ps);//取栈顶数据
int stackSize(ST* ps);//栈的大小
bool stackEmpty(ST* ps);//判断是否为空

Stack.c

#include "Stack.h"

void stackInit(ST* ps)
{
    assert(ps);
    ps->a = NULL;
    ps->top = 0;//指向初始值的下一个
    ps->capacity = 0;
}

void stackDestroy(ST* ps)
{
    assert(ps);
    free(ps->a);
    ps->a = NULL;
    ps->capacity = ps->top = 0;
}

void stackPush(ST* ps, STDataType x)
{
    assert(ps);
    if (ps->top == ps->capacity)
    {
        int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
        STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType)*newCapacity);
        if (tmp == NULL)
        {
            printf("realloc fail\n");
            exit(-1);
        }
        ps->a = tmp;
        ps->capacity = newCapacity;
    }
    ps->a[ps->top] = x;
    ps->top++;
}

void stackPop(ST* ps)
{
    assert(ps);
    assert(ps->top > 0);
    ps->top--;
}

bool stackEmpty(ST* ps)
{
    assert(ps);
    return ps->top == 0;
}

STDataType stackTop(ST* ps)
{
    assert(ps);
    assert(ps->top > 0);
    return ps->a[ps->top - 1];
}

int stackSize(ST* ps)
{
    assert(ps);
    return ps->top;
}

test.c

#include "Stack.h"
void TestStack()
{
    ST st;
    stackInit(&st);
    stackPush(&st, 1);
    stackPush(&st, 2);
    stackPush(&st, 3);
    stackPop(&st);
}

int main()
{
    TestStack();
    return 0;
}

2.队列

2.1 队列的概念及结构

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头

2.2 队列的应用场景

队列:
1.公平排队
2.广度优先遍历
栈:
1.解决括号匹配问题
2.逆波兰表达式求解
3.递归改非递归

2.3 队列的实现

队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。

首先在VS里面的源文件建立test.cQueue.c,在头文件里面建立Queue.h

Queue.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
//创建队列结构
typedef int QDataType;
//创建队列结点
typedef struct QueueNode
{
    struct QueueNode* next;//记录下一个结点
    QDataType data;//存储数据
}QNode;
//保存队头和队尾
typedef struct Queue
{
    QNode* head;//头指针
    QNode* tail;//尾指针
}Queue;

2.3.1 初始化

Queue.h

void QueueInit(Queue* pq);//初始化

Queue.c

#include "Queue.h"
void QueueInit(Queue* pq)
{
    assert(pq);
    pq->head = NULL;
    pq->tail = NULL;
}

test.c

#include "Queue.h"
void test()
{
    Queue q;
    QueueInit(&q);
}
int main()
{
    test();
    return 0;
}

调试结果:

2.3.2 销毁

Queue.h

void QueueDestroy(Queue* pq);//销毁

Queue.c

void QueueDestroy(Queue* pq)
{
    assert(pq);
    QNode* cur = pq->head;
    while (cur != NULL)
    {
        QNode* next = cur->next;
        free(cur);
        cur = next;
    }
    pq->head = pq->tail = NULL;
}

2.3.3 判空

Queue.h

bool QueueEmpty(Queue* pq);//判空

Queue.c

bool QueueEmpty(Queue* pq)
{
    assert(pq);
    return pq->head == NULL;
}

2.3.4 获取队头元素

Queue.h

QDataType QueueFront(Queue* pq);//获取队头元素

Queue.c

QDataType QueueFront(Queue* pq)
{
    assert(pq);
    assert(pq->head);//头部不能为空
    return pq->head->data;
}

2.3.5 获取队尾元素

Queue.h

QDataType QueueBack(Queue* pq);//获取队尾元素

Queue.c

QDataType QueueBack(Queue* pq)
{
    assert(pq);
    assert(pq->tail);//尾部不能为空
    return pq->tail->data;
}

2.3.6 获取队列元素个数

Queue.h

int QueueSize(Queue* pq);//获取队列元素个数

Queue.c

int QueueSize(Queue* pq)
{
    assert(pq);
    int n = 0;
    QNode* cur = pq->head;
    while (cur)
    {
        ++n;
        cur = cur->next;
    }
    return n;
}

2.3.7 入队列

Queue.h

void QueuePush(Queue* pq, QDataType x);//入队列

Queue.c

void QueuePush(Queue* pq, QDataType x)
{
    assert(pq);
    //创建一个新结点保存数据
    QNode* newnode = (QNode*)malloc(sizeof(QNode));
    //暴力检测newnode,因为malloc的都要检测
    assert(newnode);
    newnode->next = NULL;
    newnode->data = x;
    //如果一开始没有数据,为空的情况
    if (pq->tail == NULL)
    {
        assert(pq->head == NULL);
        pq->head = pq->tail = newnode;
    }
    else
    {
        pq->tail->next = newnode;
        pq->tail = newnode;
    }
}

2.3.8 出队列

Queue.h

void QueuePop(Queue* pq);//出队列

Queue.c

void QueuePop(Queue* pq)
{
    assert(pq);
    assert(pq->head && pq->tail);//tail和head均不能为空
    //特殊:当删到head=tail位置时,tail会变成野指针
    if (pq->head->next == NULL)
    {
        free(pq->head);
        pq->head = pq->tail = NULL;
    }
    //一般情况
    else
    {
        //保存head的下一个结点
        QNode* next = pq->head->next;
        free(pq->head);
        pq->head = next;
    }
}

2.4 完整代码展示

Queue.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
//创建队列结构
typedef int QDataType;
//创建队列结点
typedef struct QueueNode
{
    struct QueueNode* next;//记录下一个结点
    QDataType data;//存储数据
}QNode;
//保存队头和队尾
typedef struct Queue
{
    QNode* head;//头指针
    QNode* tail;//尾指针
}Queue;
void QueueInit(Queue* pq);//初始化
void QueueDestroy(Queue* pq);//销毁
void QueuePush(Queue* pq, QDataType x);//入队列
void QueuePop(Queue* pq);//出队列
QDataType QueueFront(Queue* pq);//获取队头元素
QDataType QueueBack(Queue* pq);//获取队尾元素
int QueueSize(Queue* pq);//元素个数
bool QueueEmpty(Queue* pq);//判空

Queue.c

#include "Queue.h"
void QueueInit(Queue* pq)
{
    assert(pq);
    pq->head = NULL;
    pq->tail = NULL;
}

void QueueDestroy(Queue* pq)
{
    assert(pq);
    QNode* cur = pq->head;
    while (cur != NULL)
    {
        QNode* next = cur->next;
        free(cur);
        cur = next;
    }
    pq->head = pq->tail = NULL;
}

bool QueueEmpty(Queue* pq)
{
    assert(pq);
    return pq->head == NULL;
}

void QueuePush(Queue* pq, QDataType x)
{
    assert(pq);
    //创建一个新结点保存数据
    QNode* newnode = (QNode*)malloc(sizeof(QNode));
    //暴力检测newnode,因为malloc的都要检测
    assert(newnode);
    newnode->next = NULL;
    newnode->data = x;
    //如果一开始没有数据,为空的情况
    if (pq->tail == NULL)
    {
        assert(pq->head == NULL);
        pq->head = pq->tail = newnode;
    }
    else
    {
        pq->tail->next = newnode;
        pq->tail = newnode;
    }
}

void QueuePop(Queue* pq)
{
    assert(pq);
    assert(pq->head && pq->tail);//tail和head均不能为空
    //特殊:当删到head=tail位置时,tail会变成野指针
    if (pq->head->next == NULL)
    {
        free(pq->head);
        pq->head = pq->tail = NULL;
    }
    //一般情况
    else
    {
        //保存head的下一个结点
        QNode* next = pq->head->next;
        free(pq->head);
        pq->head = next;
    }
}


QDataType QueueFront(Queue* pq)
{
    assert(pq);
    assert(pq->head);//头部不能为空
    return pq->head->data;
}

QDataType QueueBack(Queue* pq)
{
    assert(pq);
    assert(pq->tail);//尾部不能为空
    return pq->tail->data;
}

int QueueSize(Queue* pq)
{
    assert(pq);
    int n = 0;
    QNode* cur = pq->head;
    while (cur)
    {
        ++n;
        cur = cur->next;
    }
    return n;
}

test.c

#include "Queue.h"

void test()
{
    Queue q;
    QueueInit(&q);
    //插入数据
    QueuePush(&q, 1);
    QueuePush(&q, 2);
    QueuePush(&q, 3);
    //打印数据
    while (!QueueEmpty(&q))
    {
        printf("%d ", QueueFront(&q));
        QueuePop(&q);
    }
    printf("\n");
}

int main()
{
    test();
    return 0;
}

  • 32
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 34
    评论
评论 34
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值