栈 和 队列

一. 栈

1.什么是栈
  • 栈是一种特殊的线性表,栈有两端可以分为栈顶和栈底,栈只允许在栈顶进行元素的插入和删除,栈的元素要遵循后进先出的原则
  • 栈的插入操作叫做进栈/入栈/压栈,栈的删除操作叫做出栈,入数据和出数据都在栈顶

2.栈的实现
  • 栈的实现可以使用数组或者链表实现,使用数组实现栈更加的合理,因为数组在尾插时消耗更小
  • 栈实现使用结构体,结构体成员有指定类型( StackDataType)的指针a相当于数组,成员还有top来记录栈顶的位置和capacity记录数据的最大容量

typedef int StackDataType;

typedef struct Stack
{
    StackDataType* a;
    int top;
    int capacity;

}Stack;
//类似链表的结构

  • 初始化栈:将指针a初始化为空指针,栈顶位置top初始化为0,栈的最大容量capacity初始化为0

void StackInit(Stack* pc)
//初始化栈
{
    assert(pc);
    pc->a = NULL;
    pc->top = 0;
    pc->capacity = 0;
}

  •  入栈:首先检查栈顶的位置top是否已经增长到最大容量(capacity(pc->capacity == pc->top),如果相等,使用realloc函数扩容到NewCapacityStackDataType类型的空间。再将栈顶元素设置为x,栈顶的位置( pc->top++)
  • 在给NewCapacity赋值的时候使用了三目运算符(NewCapacity = pc->capacity == 0 ? 4 : pc->capacity * 2 ),这个代码的意思是如果最大容量Capacity==0,也就是第一次入栈时,把NewCapacity赋值为4,之后每次扩容NewCapacity每次变成二倍 

void StackPush(Stack* pc, StackDataType x)
//入栈
{
    assert(pc);

    //CapacityCheck函数
    if (pc->capacity == pc->top)
    {
        int NewCapacity = pc->capacity == 0 ? 4 : pc->capacity * 2;
        StackDataType* tmp = (StackDataType*)realloc(pc->a,sizeof(StackDataType) * NewCapacity);
        if (tmp == NULL)
        {
            perror("realloc");
            exit(-1);
        }
        pc->a = tmp;
        pc->capacity = NewCapacity;
    }
    pc->a[pc->top] = x;
    pc->top++;

}

  • 出栈:这里出栈不需要真正的把栈顶的元素删除掉,直接让栈顶的位置top向下移动一个数据的位置即可,之后就算要入栈时添加的数据也会把原来没有删除的数据覆盖掉

void StackPop(Stack* pc)
//出栈
{
    assert(pc);
    assert(pc->top > 0);
    pc->top--;

  •  获取栈顶元素:要注意栈顶的位置会比对应的数组下标大一,比如:第一个数入栈的时候( pc->a[pc->top] = x),此时top的值为0,然后pc->top++,top变成了1。所以栈顶的位置会比对应的数组下标大一

 StackDataType StackTop(Stack* pc)
//获取栈顶元素
{
    assert(pc);
    assert(pc->top > 0);
    return pc->a[pc->top-1];
}

  • 检测栈是否为空 :直接返回pc->top == 0即可

int StackEmpty(Stack* pc)
//检测栈是否为空

//为空返回非零结果,不为空则返回0
{
    assert(pc);

    return pc->top == 0;
}

  • 销毁栈:使用free函数释放a指向的申请的空间,把topcapacity全部初始化为0

void StackDestory(Stack* pc)
//销毁栈
{
    assert(pc);
    free(pc->a);
    pc->top = pc->capacity = 0;

}


 二. 队列

1.什么是队列
  • 队列也是一种特殊的线性表,队列有两端叫做队头和队尾,队列只允许在队尾插入数据,在队头进行数据删除,队列具有先进先出的特性

2.队列的实现
  • 队列也可以使用数组和链表结构实现,但是用链表使用更合适。因为如果使用数组,在出队列时把第一个元素拿出去后,后面的数据要依次向前挪动,使用数组性能不高,所以要使用链表实现
  • 队列使用链表实现,链表的每一个节点都是结构体,结构体成员Data存储QlistData类型的数据,成员next存储该节点指向下一个节点的地址(如果该节点是最后一个节点,那么该节点next=NULL)。队列还需要指向QlistNode类型的队首指针front和指向队尾的指针rear,还有记录数据个数的变量size

typedef int QlistData;
typedef struct QlistNode
{
    QlistData Data;
    struct QlistNode* next;

}QlistNode;
//每一个节点的类型

typedef struct Queue
{
    QlistNode* front;
    QlistNode* rear;
    int size;
}Queue;
//定义队尾和队首

  • 队列初始化:将指向队首和队尾的指针frontrear置为空指针,队列的数据个数size=0

void QlistInit(Queue* pc)
//队列初始化
{
    assert(pc);
    pc->front = pc->rear = NULL;
    pc->size = 0;

  • 入队列:首先创建一个新节点(使用动态内存开辟),把节点的值设置为x( NewNode->Data = x),再把节点的next指针置成空指针,如果是第一次入队列要把rearfront指针都指向新节点,如果不是第一次入队列,让原队列队尾指针rear指向的节点指向新节点(pc->rear->next = NewNode),再让队尾指针rear指向新节点

void QlistPush(Queue* pc, QlistData x)
//入队列
{
    assert(pc);
    //这里-----------------------------------------------------
    QlistNode* NewNode = (QlistNode*)malloc(sizeof(QlistNode));
    if (NewNode == NULL)
    {
        perror("QlistPush");
        exit(-1);
    }
    NewNode->Data = x;
    NewNode->next = NULL;
    //从上到下其实是QlistBuy创建一个新的节点-------------------
    if (pc->rear == NULL)//此时队列为空
    {
        pc->rear = pc->front = NewNode;
    }
    else
    {
        pc->rear->next = NewNode;
        pc->rear = pc->rear->next;
    }
    ++pc->size;

  •  出队列:断言队列不为空(assert(!QlistEmpty(pc))),如果队列中只有一个节点,那么释放该节点时,将队首和队尾指针置空(pc->rear = pc->front = NULL),如果队列中不止一个节点时,使用一个指针cur存储队首指针,队首指针向后一个节点,然后释放cur指向的节点并将cur置为空指针,最后别忘了zise--


void QlistPop(Queue* pc)
//出队列
{
    assert(pc);
    assert(!QlistEmpty(pc));
    if (pc->rear == pc->front)
    {
        free(pc->front);
        pc->rear = pc->front = NULL;
    }
    else
    {
        QlistNode* cur = pc->front;
        pc->front = pc->front->next;
        free(cur);
        cur = NULL;
    }
    --pc->size;
}

  •  判断队列是否为空:直接返回pc->front == NULL即可

bool QlistEmpty(Queue* pc)
//判断队列是否为空
{
    assert(pc);
    return pc->front == NULL;

  •  获取队首元素:直接返回pc->front->Data即可

QlistData QlistFront(Queue* pc)
//获取队首元素
{
    assert(pc);
    assert(!QlistEmpty(pc));

    return pc->front->Data;

}

  •  获取队尾元素:直接返回pc->rear->Data即可

QlistData QlistBack(Queue* pc)
//获取队尾元素
{
    assert(pc);
    assert(!QlistEmpty(pc));

    return pc->rear->Data;
}

  •  获取有效元素的个数:直接返回pc->size即可

int QlistSize(Queue* pc)
//获取有效元素的个数
{
    assert(pc);
 
    return pc->size;
}

  •  销毁节点:使用指针cur存储队首指针front,队首front指针一直向后移动一个节点,cur指针释放指向节点,cur指针再指向front,循环往复直到(front==NULL),最后把指针curfront置空,size=0即可

 void QlistDestory(Queue* pc)
//销毁节点
{
    assert(pc);
    QlistNode* cur = pc->front;
    while (pc->front)
    {
        pc->front = pc->front->next;
        free(cur);
        cur = pc->front;
    }
    //空间释放后指针置空
    pc->front = pc->rear = NULL;
    pc->size = 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值