1.队列
2.实现
3.OJ题
只允许在一段进行插入数据操作,在另一端进行数据删除操作的特殊线性表,队列具有先进先出FIFO(First In Firtst Out),插入操作的叫队尾,删除操作的叫队头
队列可以用数组和链表的结构实现,需要从两端出操作数据,所以用链表的结构更优一点
队列的设计需要两层结构体,一层结构体是节点结构体,另一层是队列结构
头文件
#pragma once
#include
typedef int DATATYPE;
//节点
typedef struct _Node
{
DATATYPE data;
struct _Node* next;
}Node;
//队列
typedef struct _Queue
{
struct _Node* head;
struct _Node* tail;
int size;
}Queue;
// 初始化
void Init(Queue* que);
// 入队
void Push(Queue* que, DATATYPE data);
// 出队
void Pop(Queue* que);
// 是否为空
bool Empty(Queue* que);
// 返回队首
DATATYPE Front(Queue* que);
// 返回队尾
DATATYPE Back(Queue* que);
// 队列大小
int Size(Queue* que);
// 销毁
void Destory(Queue* que);
实现文件
#include "Queue.h"
#include
#include
#include
void Init(Queue* que)
{
assert(que);
//置空
que->head = que->tail = NULL;
que->size = 0;
}
void Push(Queue* que, DATATYPE data)
{
assert(que);
Node* newnode = (Node*)malloc(sizeof(Node));
if (newnode == NULL)
{
perror("malloc fail");
return;
}
newnode->data = data;
newnode->next = NULL;
//空队,不为空
if (que->head == NULL)
{
//防止一个空,另一个不为空
assert(que->tail == NULL);
que->head = que->tail = newnode;
}
else
{
que->tail->next = newnode;
que->tail = newnode;
}
que->size++;
}
void Pop(Queue* que)
{
assert(que);
assert(!Empty(que));
//一个节点,多个节点
if (que->head->next == NULL)
{
free(que->head);
que->head = que->tail = NULL;
}
else
{
//头删
Node* del = que->head;
que->head = que->head->next;
free(del);
}
que->size--;
}
bool Empty(Queue* que)
{
assert(que);
//que.head == NULL && que.tail == NULL
return que->size == 0;
}
DATATYPE Front(Queue* que)
{
assert(que);
assert(!Empty(que));
return que->head->data;
}
DATATYPE Back(Queue* que)
{
assert(que);
assert(!Empty(que));
return que->tail->data;
}
int Size(Queue* que)
{
assert(que);
return que->size;
}
void Destory(Queue* que)
{
assert(que);
Node* cur = que->head;
while (cur != NULL)
{
Node* del = cur;
cur = cur->next;
free(del);
}
que->head = que->tail = NULL;
que->size = 0;
}
主文件
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
#include "Queue.h"
int main()
{
Queue que;
Init(&que);
Push(&que, 1);
Push(&que, 2);
Push(&que, 3);
Push(&que, 4);
printf("%d ", Front(&que));
printf("%d \r\n", Back(&que));
Pop(&que);
while (!Empty(&que))
{
printf("%d ", Front(&que));
printf("%d \r\n", Back(&que));
Pop(&que);
}
Destory(&que);
return 0;
}
https://leetcode.cn/problems/implement-stack-using-queues/description/
思路
利用前面写的队列。用队列实现栈的关键点在于,队列是先进先出,栈是先进后出。这时,可以用两个栈,需要出数据时将一个栈的所有数据捯到另一个栈中,留下最后一个数据,然后出队,这个就是栈的栈顶元素。每次需要出数据反复这样。入数据时,找一个不为空的入,不为空的出数据捯一遍后,刚好剩下刚进入的数据,栈为空也可以这样
//引入队列
#include
#include
#include
#include
typedef int DATATYPE;
//节点
typedef struct _Node
{
DATATYPE data;
struct _Node* next;
}Node;
//队列
typedef struct _Queue
{
struct _Node* head;
struct _Node* tail;
int size;
}Queue;
void Init(Queue* que)
{
assert(que);
//置空
que->head = que->tail = NULL;
que->size = 0;
}
void Push(Queue* que, DATATYPE data)
{
assert(que);
Node* newnode = (Node*)malloc(sizeof(Node));
if (newnode == NULL)
{
perror("malloc fail");
return;
}
newnode->data = data;
newnode->next = NULL;
//空队,不为空
if (que->head == NULL)
{
//防止一个空,另一个不为空
assert(que->tail == NULL);
que->head = que->tail = newnode;
}
else
{
que->tail->next = newnode;
que->tail = newnode;
}
que->size++;
}
bool Empty(Queue* que)
{
assert(que);
//que.head == NULL && que.tail == NULL
return que->size == 0;
}
void Pop(Queue* que)
{
assert(que);
assert(!Empty(que));
//一个节点,多个节点
if (que->head->next == NULL)
{
free(que->head);
que->head = que->tail = NULL;
}
else
{
//头删
Node* del = que->head;
que->head = que->head->next;
free(del);
}
que->size--;
}
DATATYPE Front(Queue* que)
{
assert(que);
assert(!Empty(que));
return que->head->data;
}
DATATYPE Back(Queue* que)
{
assert(que);
assert(!Empty(que));
return que->tail->data;
}
int Size(Queue* que)
{
assert(que);
return que->size;
}
void Destory(Queue* que)
{
assert(que);
Node* cur = que->head;
while (cur != NULL)
{
Node* del = cur;
cur = cur->next;
free(del);
}
que->head = que->tail = NULL;
que->size = 0;
}
//------------------------------------------------------------------------
//实现栈
typedef struct {
Queue que1;
Queue que2;
} MyStack;
MyStack* myStackCreate() {
MyStack* stk = (MyStack*)malloc(sizeof(MyStack));
Init(&stk->que1);
Init(&stk->que2);
return stk;
}
void myStackPush(MyStack* obj, int x) {
//往空队列插入
if(Empty(&obj->que1))
Push(&obj->que1, x);
else
Push(&obj->que2, x);
}
int myStackPop(MyStack* obj) {
//定义空和非空,如果错误交换
Queue* empty = &obj->que1;
Queue* noempty = &obj->que2;
if(Empty(&obj->que2))
{
empty = &obj->que2;
noempty = &obj->que1;
}
//非空的大于1个往另一个队列捯
while(Size(noempty) > 1)
{
Push(empty, Front(noempty));
Pop(noempty);
}
int x = Front(noempty);
Pop(noempty);
return x;
}
int myStackTop(MyStack* obj) {
//定义空和非空,如果错误交换
Queue* empty = &obj->que1;
Queue* noempty = &obj->que2;
if(Empty(&obj->que2))
{
empty = &obj->que2;
noempty = &obj->que1;
}
return Back(noempty);
}
bool myStackEmpty(MyStack* obj) {
return Empty(&obj->que1) && Empty(&obj->que2);
}
void myStackFree(MyStack* obj) {
Destory(&obj->que1);
Destory(&obj->que2);
free(obj);
}
/**
* Your MyStack struct will be instantiated and called as such:
* MyStack* obj = myStackCreate();
* myStackPush(obj, x);
* int param_2 = myStackPop(obj);
* int param_3 = myStackTop(obj);
* bool param_4 = myStackEmpty(obj);
* myStackFree(obj);
*/
https://leetcode.cn/problems/implement-queue-using-stacks/
思路
利用实现的栈。栈实现队列同样需要两个栈,由于栈是先进后出,当我们捯一遍数据后,刚好会把所有数据顺序反过来,所以只需要捯一次。利用这种特性,可以将两个栈分为只仅数据的和出数据的。刚开始出栈为空,需要出数据时,从入栈捯数据过来然后出栈顶元素
//引用栈结构
#include
#include
#include
#include
typedef int DATATYPE;
typedef struct _Stack
{
DATATYPE* ary;
int top; //指向下一个存放数据的位置
int capacity;
}Stk;
void Init(Stk* stack)
{
assert(stack);
stack->ary = NULL;
stack->top = 0; //指向栈顶下一个位置
stack->capacity = 0;
}
void Push(Stk* stack, DATATYPE data)
{
assert(stack);
//需要扩容
if (stack->top == stack->capacity)
{
int newcap = stack->capacity == 0 ? 4 : stack->capacity * 2;
DATATYPE* temp = (DATATYPE*)realloc(stack->ary, sizeof(DATATYPE) * newcap);
if (temp == NULL)
{
perror("realloc fail");
return;
}
stack->ary = temp;
stack->capacity = newcap;
}
//存数据
stack->ary[stack->top] = data;
stack->top++;
}
bool Empty(Stk* stack)
{
assert(stack);
return stack->top == 0;
}
void Pop(Stk* stack)
{
assert(stack);
assert(!Empty(stack));
stack->top--;
}
DATATYPE Top(Stk* stack)
{
assert(stack);
assert(!Empty(stack));
return stack->ary[stack->top - 1];
}
int Size(Stk* stack)
{
assert(stack);
return stack->top;
}
void Destory(Stk* stack)
{
assert(stack);
free(stack->ary);
stack->ary = NULL;
stack->capacity = 0;
stack->top = 0;
}
//------------------------------------------------------------------------
//实现队列
typedef struct {
Stk stpush;
Stk stpop;
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
Init(&obj->stpush);
Init(&obj->stpop);
return obj;
}
void myQueuePush(MyQueue* obj, int x) {
Push(&obj->stpush, x);
}
int myQueuePop(MyQueue* obj) {
int ch = myQueuePeek(obj);
Pop(&obj->stpop);
return ch;
}
int myQueuePeek(MyQueue* obj) {
if(Empty(&obj->stpop))
{
while(!Empty(&obj->stpush))
{
Push(&obj->stpop, Top(&obj->stpush));
Pop(&obj->stpush);
}
}
return Top(&obj->stpop);
}
bool myQueueEmpty(MyQueue* obj) {
return Empty(&obj->stpush) && Empty(&obj->stpop);
}
void myQueueFree(MyQueue* obj) {
Destory(&obj->stpush);
Destory(&obj->stpop);
free(obj);
}
/**
* Your MyQueue struct will be instantiated and called as such:
* MyQueue* obj = myQueueCreate();
* myQueuePush(obj, x);
* int param_2 = myQueuePop(obj);
* int param_3 = myQueuePeek(obj);
* bool param_4 = myQueueEmpty(obj);
* myQueueFree(obj);
*/
https://leetcode.cn/problems/design-circular-queue/
思路
环形队列用数组来实现。如果空间大小是8,就存7个元素,最后一个元素用来判断是否满了,用front和reor两个下标记录队头和队尾。删除就增加front,插入增加rero,如果这两个有一个超过了k,也就是总元素大小,就重新置为0
typedef struct {
int* ary;
int front;
int reor;
int k;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* que = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
que->ary = (int*)malloc(sizeof(int) * (k + 1));
que->front = que->reor = 0;
que->k = k;
return que;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->reor == obj->front;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
return (obj->reor + 1) % (obj->k + 1) == obj->front;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if (!myCircularQueueIsFull(obj)) {
obj->ary[obj->reor] = value;
obj->reor++;
obj->reor = obj->reor % (obj->k + 1);
return true;
}
return false;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if (!myCircularQueueIsEmpty(obj)) {
obj->front++;
obj->front = obj->front % (obj->k + 1);
return true;
}
return false;
}
int myCircularQueueFront(MyCircularQueue* obj) {
if (myCircularQueueIsEmpty(obj))
return -1;
return obj->ary[obj->front];
}
int myCircularQueueRear(MyCircularQueue* obj) {
if (myCircularQueueIsEmpty(obj))
return -1;
// return obj->ary[(obj->reor + obj->k) % (obj->k + 1)]
if (obj->reor == 0)
return obj->ary[obj->k];
return obj->ary[obj->reor - 1];
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->ary);
free(obj);
}
平常情况下reor-front就可以算出长度,但如果reor循环加到front的左边,这时候就要加数组的长度%N取到长度