这节课讲的是循环队列:
一共需要知道三个要点:
第一个:为了使队列的入队和出队的时间复杂度都为O(1),所以我们需要将其臆想成一个环形。
第二个:判空和判满操作的判断依据出现了冲突,都是rear==front; 所以我们需要浪费一个尾部节点,
当做标记位,当尾指针再向后跑一步就遇到了头指针,此时我们就认为队列满了。
第三个:求队列有效元素个数的公式为:(rear - front + MAXQSIZE) % MAXQSIZE,
加上一个MAXQSIZE的作用是为了防止(rear-front)出现负数,后边的%MAXQSIZE的作用是防止多加了一个MAXQSIZE。
想办法让队尾队头的时间复杂度都为O(1)
尾取4取不到则对其取模 得0 ; 出队与其代码类似。
记住 队列的有效元素个数的公式。
循环队列 头文件 queue.h
#pragma once
typedef int ELEM_TYPE;
#define MAXQSIZE 100
typedef struct Queue
{
ELEM_TYPE *base;//数据域 指向malloc申请来的动态内存
int front;//头指针,当队列不空的时间,保存是队头,指向的第一个元素的下标
int rear;//尾指针,当队列不空的时间,保存的是队尾,指向的下一个元素入队的下标
//int length;//有效元素个数
}Queue, *PQueue;
//初始化
void Init_Queue(PQueue pq);
//入队 push
bool Push(PQueue pq, ELEM_TYPE val);
//出队 pop 需要删除操作
bool Pop(PQueue pq, ELEM_TYPE *rtval);
//top 获取队头元素值, 不需要删除操作
bool Top(PQueue pq, ELEM_TYPE *rtval);
//获取其有效元素个数
int Get_length(PQueue pq);
//判空
bool IsEmpty(PQueue pq);
//判满
bool IsFull(PQueue pq);
//清空
void Clear(PQueue pq);
//销毁
void Destroy(PQueue pq);
void Show(PQueue pq);
queue.cpp
#include <stdio.h>
#include <assert.h>
#include <malloc.h>
#include "queue.h"
/*
队列:一种先进先出FIFO(后进后出)的线性表,类比现实生活中的排队
//一端入,另一端出,入队的一端叫做队尾,出队的一端叫做队头。
//当队列中没有一个元素时,叫做空队。
难点:1.如何将队列的入队以及出队时间复杂度都降低为O(1)?
//火车:售货员怎么卖东西? 推车小车,放着瓜子花生矿泉水。
//模仿一下:我们数据不需要挪动,而是是让队头指针以及队尾指针来回走动,得把它臆想成一个环状
2.怎么将判空和判满操作区分开?
//2.1:浪费一个尾部空间,当做标记位,当(rear+1)%MAXSIZE == front; 我们就认为已满
//2.2:在结构体里多申请一个变量,当做标记位,保存的是队列的有效元素个数
3.怎么获取其队列有效元素个数?求队列的有效元素个数的公式是啥?
// (rear - front + MAXQSIZE) % MAXQSIZE
这节课讲的是循环队列:
//一共需要知道三个要点:
第一个:为了使队列的入队和出队的时间复杂度都为O(1),所以我们需要将其臆想成一个环形
第二个:判空和判满操作的判断依据出现了冲突,都是rear==front; 所以我们需要浪费一个尾部节点,
当做标记位,当尾指针再向后跑一步就遇到了头指针,此时我们就认为队列满了
第三个:求队列有效元素个数的公式为:(rear - front + MAXQSIZE) % MAXQSIZE,
加上一个MAXQSIZE的作用是为了防止(rear-front)出现负数,后边的%MAXQSIZE的作用是防止多加了
*/
//初始化
void Init_Queue(PQueue pq)
{
//assert
pq->base = (ELEM_TYPE *)malloc(sizeof(ELEM_TYPE) * MAXQSIZE);
assert(pq->base != NULL);
pq->front = 0;
pq->rear = 0;
//pq->front = pq->rear = 0;
}
//入队 push
bool Push(PQueue pq, ELEM_TYPE val)
{
//assert pq rtval
//如果队列已满 则入队不进去
if(IsFull(pq))
return false;
pq->base[pq->rear] = val;
//把它臆想成了一个环,所以rear向后跑的代码会有不同
//pq->rear++;//ok? error
pq->rear = (pq->rear+1)%MAXQSIZE;
return true;
}
//出队 pop 需要删除操作
bool Pop(PQueue pq, ELEM_TYPE *rtval)
{
//assert
//如果队列为空 则不需要出队
if(IsEmpty(pq))
return false;
*rtval = pq->base[pq->front];
//把它臆想成了一个环,所以front向后跑的代码会有不同
//pq->front++;//error
pq->front = (pq->front+1)%MAXQSIZE;
return true;
}
//top 获取队头元素值, 不需要删除操作
bool Top(PQueue pq, ELEM_TYPE *rtval)
{
//assert
//如果队列为空 则不需要出队
if(IsEmpty(pq))
return false;
*rtval = pq->base[pq->front];
//不需要将front指针改变
return true;
}
//获取其有效元素个数
int Get_length(PQueue pq)
{
//assert
int length = (pq->rear - pq->front + MAXQSIZE) % MAXQSIZE;
return length;
}
//判空
bool IsEmpty(PQueue pq)
{
return pq->front == pq->rear;
}
//判满
bool IsFull(PQueue pq)
{
return (pq->rear+1)%MAXQSIZE == pq->front;
}
//清空
void Clear(PQueue pq)
{
//assert
pq->front = pq->rear = 0;
}
//销毁
void Destroy(PQueue pq)
{
//assert
free(pq->base);
pq->base = NULL;
pq->front = pq->rear = 0;
}
void Show(PQueue pq)
{
for(int i=pq->front; i!=pq->rear; i=(i+1)%MAXQSIZE)
{
printf("%d ", pq->base[i]);
}
printf("\n");
}