07 队列

目录

1.队列
2.实现
3.OJ题


1. 队列

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

在这里插入图片描述

2. 实现

队列可以用数组和链表的结构实现,需要从两端出操作数据,所以用链表的结构更优一点

在这里插入图片描述

队列的设计需要两层结构体,一层结构体是节点结构体,另一层是队列结构

头文件

#pragma once
#include <stdbool.h>

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 <stdio.h>
#include <stdlib.h>
#include <assert.h>

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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#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;
}


3. OJ题

3.1 用队列实现栈

https://leetcode.cn/problems/implement-stack-using-queues/description/
在这里插入图片描述

思路
利用前面写的队列。用队列实现栈的关键点在于,队列是先进先出,栈是先进后出。这时,可以用两个栈,需要出数据时将一个栈的所有数据捯到另一个栈中,留下最后一个数据,然后出队,这个就是栈的栈顶元素。每次需要出数据反复这样。入数据时,找一个不为空的入,不为空的出数据捯一遍后,刚好剩下刚进入的数据,栈为空也可以这样

在这里插入图片描述

//引入队列
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

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);
*/

3.2 栈实现队列

https://leetcode.cn/problems/implement-queue-using-stacks/

在这里插入图片描述

思路
利用实现的栈。栈实现队列同样需要两个栈,由于栈是先进后出,当我们捯一遍数据后,刚好会把所有数据顺序反过来,所以只需要捯一次。利用这种特性,可以将两个栈分为只仅数据的和出数据的。刚开始出栈为空,需要出数据时,从入栈捯数据过来然后出栈顶元素

在这里插入图片描述

//引用栈结构
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

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);
*/

3.3 环形队列

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取到长度

在这里插入图片描述
下面的就是(1-3+6)%6 =4,存了4个数据

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值