IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 数据结构 - C语言队列的基本操作 -> 正文阅读

[数据结构与算法]数据结构 - C语言队列的基本操作

目录

前言:

队列的概念及结构

队列的实现

队列的定义

接口函数

实现接口函数

完整代码

????????Queue.h

????????Queue.c

栈与队列的OJ练习

T1、用队列实现栈

T2、用栈实现队列

T3、设计循环队列

栈和队列的用途


前言:

队列的概念及结构

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

入队列:进行插入操作的一端称为队尾

出队列:进行删除操作的一端称为队头?

队列的实现

队列可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低,因为要从后面向前进行覆盖数据。

队列的定义

typedef int QDataType;

typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}QNode;

typedef struct Queue
{
	QNode* head;
	QNode* tail;

	//size_t size;
}Queue;

????????这里我们以单链表为基础,再定义一个头指针?head?一个尾指针?tail?,这两个指针才有意义。因为根据队列的性质,我们只会在队尾插,不会再队尾删。所以这个尾指针的价值就得到了完美的体现,实际中定义几个指针是看你的需求确定的

?接口函数

void QueueInit(Queue* pq);
void QueueDestory(Queue* pq);
void QueuePush(Queue* pq, QDataType x);
void QueuePop(Queue* pq);
bool QueueEmpty(Queue* pq);
size_t QueueSize(Queue* pq);
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);

实现接口函数

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = pq->tail = NULL;
}

void QueueDestory(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}

	pq->head = pq->tail = NULL;
}

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	assert(newnode);

	newnode->data = x;
	newnode->next = NULL;

	if (pq->tail == NULL)    //第一个元素
	{
		assert(pq->head == NULL);
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
}

void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->head && pq->tail);

	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	else
	{
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
}

bool QueueEmpty(Queue* pq)
{
	assert(pq);

	//return pq->head == NULL && pq->tail == NULL;
	return pq->head == NULL;
}

size_t QueueSize(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	size_t size = 0;
	while (cur)
	{
		size++;
		cur = cur->next;
	}

	return size;
}

QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->head);

	return pq->head->data;
}

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->tail);

	return pq->tail->data;
}

完整代码

Queue.h

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>

typedef int QDataType;

//typedef struct QueueNode
//{
//	QDataType data;
//	struct QueueNode* next;
//}QNode, *PNode;

typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}QNode;

typedef struct Queue
{
	QNode* head;
	QNode* tail;

	//size_t size;
}Queue;

void QueueInit(Queue* pq);
void QueueDestory(Queue* pq);
void QueuePush(Queue* pq, QDataType x);
void QueuePop(Queue* pq);
bool QueueEmpty(Queue* pq);
size_t QueueSize(Queue* pq);
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);

Queue.c

接口函数加 #include "Queue.h" 即可

栈与队列的OJ练习

强烈建议先看:数据结构 - c语言栈的基本操作

T1、用队列实现栈

225. 用队列实现栈

?思路:

1、入栈,push数据到不为空的队列
2、出栈,把不为空的队列的数据前N-1导入另一个空队列,最后剩下的一个删掉。

本质:保持一个队列存储数据,另外一个队列空着,要出栈时,空队列用来倒数据
?

typedef int QDataType;
typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}QNode;
typedef struct Queue
{
	QNode* head;
	QNode* tail;
}Queue;
void QueueInit(Queue* pq);
void QueueDestory(Queue* pq);
void QueuePush(Queue*pq,QDataType x);
void QueuePop(Queue*pq);
size_t QueueSize(Queue* pq);
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);
bool QueueEmpty(Queue* pq);
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head =pq->tail = NULL;
}
QNode* BuyQNode(QDataType x)
{
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		printf("fail malloc\n");
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QNode* newnode = BuyQNode(x);
	if (pq->tail == NULL)
	{
		assert(pq->head == NULL);
		pq->head= pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
	
}
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->tail&&pq->head);
	if (pq->head->next==NULL)//处理只有一个节点的时候
	{
		free(pq->tail);
		pq->tail = pq->head = NULL;
	}
	else//有多个节点
	{
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
}
size_t QueueSize(Queue* pq)
{
	assert(pq);
	size_t size = 0;
	QNode* cur = pq->head;
	while (cur!= pq->tail->next)
	{
		size++;
		cur = cur->next;
	}
	return size;
}
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->head);
	return pq->head->data;
}
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->tail);
	return pq->tail->data;
}
void QueueDestory(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
}
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->head==NULL&&pq->tail==NULL;
}
typedef struct {
    Queue q1;
    Queue q2;
} MyStack;


MyStack* myStackCreate() {
    MyStack* pst = (MyStack*)malloc(sizeof(MyStack));
    assert(pst);
    QueueInit(&pst->q1);//这一行代码和后面这一行代码等价:QueueInit(&(pst->q1));
    QueueInit(&pst->q2);//这一行代码和后面这一行代码等价:QueueInit(&(pst->q2));
    return pst;
}

void myStackPush(MyStack* obj, int x) {
    assert(obj);
    if(!QueueEmpty(&obj->q1))
    {
        QueuePush(&obj->q1,x);
    }
    else
    {
        QueuePush(&obj->q2,x);
    }
}

int myStackPop(MyStack* obj) {
    assert(obj);
    Queue *emptyQ = &obj->q1;
    Queue*nonEmptyQ = &obj->q2;
    if(!QueueEmpty(&obj->q1))
    {
        emptyQ = &obj->q2;
        nonEmptyQ = &obj->q1;
    }
    //把非空队列的前N个数据,导入空队列,剩下一个删掉
    //就实现了后进先出
    while(QueueSize(nonEmptyQ)>1)
    {
        QueuePush(emptyQ,QueueFront(nonEmptyQ));//将非空队列的队头数据push到非空队列中
        QueuePop(nonEmptyQ);//将非空队列的队头数据出队
    }
    QDataType top = QueueFront(nonEmptyQ);
    QueuePop(nonEmptyQ);
    return top;
}

int myStackTop(MyStack* obj) {
    assert(obj);
    
    if(!QueueEmpty(&obj->q1))
    {
        return QueueBack(&obj->q1);
    }
    else
    {
        return QueueBack(&obj->q2);
    }
   
}
bool myStackEmpty(MyStack* obj) {
    assert(obj);
    return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2);
}

void myStackFree(MyStack* obj) {
    assert(obj);
    QueueDestory(&obj->q1);
    QueueDestory(&obj->q2);
    free(obj);
}

T2、用栈实现队列

232. 用栈实现队列

思路:

建立两个栈,一个栈用来入队叫做pushST,一个栈用来出队,叫做popST;
在队popST中的数据进行操作(出队)时,如果popST中没有数据就将pushST中的数据都推送到popST中

typedef int STDataType;
//数组栈的实现
typedef struct Stack
{
	STDataType* a;
	int top;//栈顶的位置
	int capacity;//容量
}ST;
void StackInit(ST* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}
void StackDestory(ST*ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity =ps->top =  0;
}
void StackPush(ST* ps, STDataType x)
{
	assert(ps);
	if (ps->top == ps->capacity)//满了进行扩容
	{
		int newCapacity = ps->capacity == 0 ? 2 : 2 * ps->capacity;
		STDataType*new = (STDataType*)realloc(ps->a,sizeof(STDataType)*newCapacity);
		if (new == NULL)
		{
			printf("fail malloc\n");
			exit(-1);
		}
		ps->a = new;
		ps->capacity = newCapacity;
	}
	ps->a[ps->top++] = x;
}
void StackPop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);
	--ps->top;
}
bool StackEmpty(ST* ps)
{
	assert(ps);
	return ps->top == 0;
}
STDataType StackTop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);

	return ps->a[ps->top - 1];
}
int SizeStack(ST* ps)
{
	assert(ps);
	return ps->top;
}
void StackInit(ST*ps);
void StackDestory(ST* ps);
void StackPush(ST* ps,STDataType x);
void StackPop(ST* ps);
bool StackEmpty(ST* ps);
int SizeStack(ST* ps);
STDataType StackTop(ST* ps);
typedef struct {
    ST pushST;
    ST popST;
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue * myQueue = (MyQueue*)malloc(sizeof(MyQueue));
    assert(myQueue);
    StackInit(&myQueue->pushST);
    StackInit(&myQueue->popST);
    return myQueue;
}

void myQueuePush(MyQueue* obj, int x) {
    assert(obj);
    StackPush(&obj->pushST,x);//入队直接向pushST插入即可
}

int myQueuePop(MyQueue* obj){
    assert(obj);
    if(StackEmpty(&obj->popST))//push为空,就进行倒数据,就符合先进先出的顺序了
    {
        while(!StackEmpty(&obj->pushST))
        {
            StackPush(&obj->popST,StackTop(&obj->pushST));
            StackPop(&obj->pushST);
        }
    }
    STDataType ret = StackTop(&obj->popST);//临时保存返回的数据
    StackPop(&obj->popST);
    return ret;
}

int myQueuePeek(MyQueue* obj) {
    assert(obj);
    if(StackEmpty(&obj->popST))
    {
        while(!StackEmpty(&obj->pushST))
        {
            StackPush(&obj->popST,StackTop(&obj->pushST));
            StackPop(&obj->pushST);
        }
    }
    return StackTop(&obj->popST);
}

bool myQueueEmpty(MyQueue* obj) {
    assert(obj);
    return StackEmpty(&obj->pushST)&&StackEmpty(&obj->popST);
}

void myQueueFree(MyQueue* obj) {
    assert(obj);
    StackDestory(&obj->pushST);
    StackDestory(&obj->popST);
    free(obj);
}

注意:在上面的代码中,在进行出队操作时,只要popST这个栈中有数据,那么我们就不进行倒数据的操作(即将pushST中的数据倒到popST这个栈中),只有当pop中的数据为空且我们要进行出队时才进行倒数据

T3、设计循环队列

622. 设计循环队列

?

?tail=rear;

为了避免空和满混淆,无法区分,多开一个空间。

1. front = tail时是空

2. tail下一个位置是front时是满

?然而我们是用链表实现,所以满会有两种情况:

1、obj->tail = k && obj->head = 0

2、obj->tail+1 = obj->head

typedef struct {
    int *a;
    int head;//循环队列的头
    int tail;//循环队列的尾
    int capacity;//循环队列元素的最大数目
} MyCircularQueue;

bool myCircularQueueIsEmpty(MyCircularQueue* obj);//判断循环队列是否为空的声明
bool myCircularQueueIsFull(MyCircularQueue* obj);//判断循环队列是否为满的声明
MyCircularQueue* myCircularQueueCreate(int k) //循环队列的初始化
{
    MyCircularQueue*myCircularQ = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    assert(myCircularQ);
    int *tmp = (int*)malloc(sizeof(int)*(k+1));
    assert(tmp);
    myCircularQ->a = tmp;
    myCircularQ->head = 0;
    myCircularQ->tail = 0;
    myCircularQ->capacity = k;
    return myCircularQ;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) //向循环队列插入一个元素,如果成功插入则返回真。
{
    assert(obj);
    if(myCircularQueueIsFull(obj))//满了的情况
    {
        return false;
    }
    obj->a[obj->tail] = value;
    if(obj->tail==obj->capacity)//此时已经到达了开辟数组的最后一个位置,tail再进行++操作后会跳跃到第一个位置
    {
        obj->tail = 0;
    }
    else
    {
        ++obj->tail;
    }
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) //从循环队列中删除一个元素,如果成功删除则返回真。
{
    assert(obj);
    if(myCircularQueueIsEmpty(obj))//循环队列中为空的情况
    {
        return false;
    }
    if(obj->head==obj->capacity)//循环队列中的head在开辟的最后的一个空间位置的情况,head要发生跳跃
    {
        obj->head = 0;
    }
    else
    {
        ++obj->head;
    }
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj) //从队首获取元素,如果队列为空,返回 -1 。
{
    assert(obj);
    if(myCircularQueueIsEmpty(obj))//队列元素为空的情况
        return -1;
    return obj->a[obj->head];
}

int myCircularQueueRear(MyCircularQueue* obj)//获取队尾元素,如果队列为空,返回 -1 。
{
    assert(obj);
    if(myCircularQueueIsEmpty(obj))//循环队列元素为空的情况
        return -1;
    if(obj->tail==0)//尾在头的时候,就要返回最后一个空间的位置
    {
        return obj->a[obj->capacity];
    }
    else
    {
        return obj->a[obj->tail-1];//正常情况返回tail的前一个位置
    }
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) //判断循环队列是否满
{
    assert(obj);
    return obj->tail==obj->head;//尾下标等于头下标的时候就是空
}

bool myCircularQueueIsFull(MyCircularQueue* obj) //判断循环队列是否满
{
    assert(obj);
    if(obj->tail==obj->capacity && obj->head==0)//判断的是尾下标指向最后一块空间,头下标在最靠前的空间
    {
        return true;
    }
    else
    {
        return obj->tail+1 ==obj->head;
    }
}  

void myCircularQueueFree(MyCircularQueue* obj) //循环队列的销毁
{
    assert(obj);
    free(obj->a);
    free(obj);
}

栈和队列的用途

栈:用来解决括号匹配,逆波兰表达式的求解,递归改非递归等等。

队列:公平排队,广度优先遍历等等。

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-05-24 18:28:41  更:2022-05-24 18:30:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 1:38:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码