队列:
只有两个口进出数据,一个专门进入数据,另一个专门出数据,先进先出,FIFO表
1. 顺序队列:
数据项 :
存储元素的连续内存的首地址
容量
队头位置 (出队)
队尾位置 (入队)
[元素数量]
运算:创建、销毁、清空、出队、入队、队空、队满、队头、队尾、元素数量
需要注意的问题
1、存储元素是由一维数组+队头位置front+队尾位置rear来表示,入队rear+1,出队front+1,为了让队列能够反复使用,我们需要把一维数组想象成一个环,因此+1后都需要对容量cal求余
front = (front+1)%cal
rear = (rear+1)%cal
2、判断队空和队满问题
如果不处理该问题,那么队空和队满的条件都是 front==rear,就无法区分是队空还是队满
方法1:存储元素的内存多增加一个位置空间(常考)
队空:front==rear
队满:(rear+1)%cal == front
代价:需要额外申请存储一个元素的内存
计算数量:(rear-front+cal)%cal
队尾数据下标:(rear-1+cal)%cal
方法2:顺序队列结构中增加一个记录元素数量的数据项,通过数量与容量对比判断队空、队满
设计顺序队列
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define TYPE int
// 顺序队列结构
typedef struct ArrayQueue
{
TYPE* ptr;
size_t cal; // 容量
size_t front; // 队头位置head\begin
size_t rear; // 队尾位置tail\back
}ArrayQueue;
// 创建顺序队列
ArrayQueue* create_array_queue(size_t cal)
{
// 申请队列结构内存
ArrayQueue* queue = malloc(sizeof(ArrayQueue));
// 申请存储队列元素的内存
queue->ptr = malloc(sizeof(TYPE)*(cal+1));
// 初始化容量
queue->cal = cal+1;
queue->front = 0;
queue->rear = 0;
return queue;
}
// 销毁
void destroy_array_queue(ArrayQueue* queue)
{
free(queue->ptr);
free(queue);
}
// 队空
bool empty_array_queue(ArrayQueue* queue)
{
return queue->front == queue->rear;
}
// 队满
bool full_array_queue(ArrayQueue* queue)
{
return (queue->rear+1)%queue->cal == queue->front;
}
// 入队
bool push_array_queue(ArrayQueue* queue,TYPE data)
{
if(full_array_queue(queue)) return false;
queue->ptr[queue->rear] = data;
queue->rear = (queue->rear+1)%queue->cal;
return true;
}
// 出队
bool pop_array_queue(ArrayQueue* queue)
{
if(empty_array_queue(queue)) return false;
queue->front = (queue->front+1)%queue->cal;
return true;
}
// 队头
TYPE head_array_queue(ArrayQueue* queue)
{
return queue->ptr[queue->front];
}
// 队尾
TYPE tail_array_queue(ArrayQueue* queue)
{
return queue->ptr[(queue->rear - 1 + queue->cal)%queue->cal];
}
// 数量
size_t size_array_queue(ArrayQueue* queue)
{
return (queue->rear - queue->front + queue->cal)%queue->cal;
}
2.链式队列:
由若干个节点组成的队列结构,只能操作队头节点、队尾节点
链式队列结构:
队头指针
队尾指针
节点数量
运算:创建、销毁、队空、入队、出队、队头、队尾、数量
设计链式队列
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define TYPE int
// 节点结构
typedef struct Node
{
TYPE data;
struct Node* next;
}Node;
// 创建节点
Node* create_node(TYPE data)
{
Node* node = malloc(sizeof(Node));
node->data = data;
node->next = NULL;
return node;
}
// 设计链式队列结构
typedef struct ListQueue
{
Node* head; // 队头指针
Node* tail; // 队尾指针
size_t cnt; // 节点数量
}ListQueue;
// 创建队列
ListQueue* create_list_queue(void)
{
ListQueue* queue = malloc(sizeof(ListQueue));
queue->head = NULL;
queue->tail = NULL;
queue->cnt = 0;
return queue;
}
// 队空
bool empty_list_queue(ListQueue* queue)
{
return 0 == queue->cnt;
}
// 入队
void push_list_queue(ListQueue* queue,TYPE data)
{
Node* node = create_node(data);
if(0 == queue->cnt)
{
queue->head = node;
queue->tail = node;
}
else
{
queue->tail->next = node;
queue->tail = node;
}
queue->cnt++;
}
// 出队
bool pop_list_queue(ListQueue* queue)
{
if(empty_list_queue(queue)) return false;
Node* temp = queue->head;
queue->head = temp->next;
free(temp);
queue->cnt--;
if(0 == queue->cnt) queue->tail = NULL;
return true;
}
// 队头
TYPE head_list_queue(ListQueue* queue)
{
return queue->head->data;
}
// 队尾
TYPE tail_list_queue(ListQueue* queue)
{
return queue->tail->data;
}
// 数量
size_t size_list_queue(ListQueue* queue)
{
return queue->cnt;
}
// 销毁队列
void destroy_list_queue(ListQueue* queue)
{
while(pop_list_queue(queue));
free(queue);
}
3.队列的应用:
1、数据排队处理-消息排队
2、树的层序遍历
3、图的广度优先遍历BFS
4、封装线程池、数据池
4.常考的笔试题、面试题:(喜欢考)
请使用两个栈来模拟一个队列的出队、入队功能(栈结构的功能都已实现,可以直接使用)
typedef struct Queue
{
ArrayStack* s1;
ArrayStack* s2;
}Queue;
1、s1负责入队、s2负责出队
2、当s2为空s1非空时,出队时,从s1转移到s2,s1需要全部转移到s2
3、当s1、s2非空时,优先出s2,直到s2出完,可以继续从s1转移到s2继续出队,直到s1、s2都为空才队空。
4、s2空s1满时,入队时需要s1全部转移到s2,入s1
5、s1s2满不入队,s1满s2非空也不入队
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define TYPE int
// 设计顺序栈结构
typedef struct ArrayStack
{
TYPE* ptr;
size_t cal; // 容量
size_t top; // 栈顶位置 指向即将要入栈的位置
}ArrayStack;
// 创建
ArrayStack* create_array_stack(size_t cal)
{
// 为顺序栈结构分配内存
ArrayStack* stack = malloc(sizeof(ArrayStack));
// 为存储数据元素分配内存
stack->ptr = malloc(sizeof(TYPE)*cal);
stack->cal = cal;
stack->top = 0;
return stack;
}
// 销毁
void destroy_array_stack(ArrayStack* stack)
{
free(stack->ptr);
free(stack);
}
// 栈空
bool empty_array_stack(ArrayStack* stack)
{
return !stack->top;
}
// 栈满
bool full_array_stack(ArrayStack* stack)
{
return stack->top >= stack->cal;
}
// 入栈
bool push_array_stack(ArrayStack* stack,TYPE data)
{
if(full_array_stack(stack)) return false;
stack->ptr[stack->top++] = data;
return true;
}
// 出栈
bool pop_array_stack(ArrayStack* stack)
{
if(empty_array_stack(stack)) return false;
stack->top--;
return true;
}
// 栈顶
bool top_array_stack(ArrayStack* stack,TYPE* data)
{
if(empty_array_stack(stack)) return false;
*data = stack->ptr[stack->top-1];
return true;
}
// 数量
size_t size_array_stack(ArrayStack* stack)
{
return stack->top;
}
标签:return,队列,queue,cal,array,stack,rear
From: https://www.cnblogs.com/wangqiuji/p/17640940.html