( 从零开始的数据结构生活 )三、队列

队列


今天我们一起学习队列。
今天 一起来学习印度老哥Harsha Suryanarayana的数据结构,并对学习过程中有问题的点进行描述。
原创点:第1节,第2节,第3节涉及的代码均由笔者亲自“操刀”,第4节的代码引用Harsha的代码。

1. 队列的介绍


定义:
和栈大差不差,但也具有一定的限制——插入元素只能从队尾进行,而删除从另一端进行,即队头。
操作:
(1)Push/EnQueue:从队尾插入一个元素。
(2)PoP/DeQueue :从队头删除一个元素。
(3)Peek/front:简单地查看(返回)队列的头部元素。
(4)IsEmpty:判断队列是否为空。
(5)IsFull:如果队列有大小,检查队列是否已满。
以上操作的时间复杂度都 为O(1)。



2. 用数组实现队列

队列也有两种方法进行实现:数组和链;
我们首先拿数组实现队列;


队列的定义和初始化:

#define MAXSIZE 100
struct Queue
{
	int data[MAXSIZE];
	int head;
	int rear;
};
struct Queue* q;
void Init()
{
	q->head = q->rear = 0;
}

代码解释:
首先是 struct Queue 的解释:我为什么要定义 head 和 rear 这两个整型变量,data用来存储数据,head 用来确定队头,rear 用来确定队尾;
其次是 Init 函数,对其 head 和 rear 进行初始化,确保目前这个队列为空。


IsEmpty函数:

int IsEmpty()
{
	if(q->head == q->rear)
		return 1;
	return 0;
}

IsFull函数:

int IsFull()
{
	if(q->rear == MAXSIZE && q->rear != q->head)
		return 1;
	return 0;
}

两个代码,我一起解释:
首先明确这两个函数的return值
如果函数return 1 那么我们认为这个队列是空(满);相反如果函数 return 0,那么我们认为这个队列是有元素的;
其次是我对于这两个函数的判断:
如果q->head 等于 q->rear,即头尾指向同一个元素,那么这个队列是空的;如果 q->rear 处于数组的最后且 q->head 不等于 q->rear,那么我们认为这个数组是满的。


EnQueue函数:

void EnQueue(int  x)
{
	if(q->rear == MAXSIZE)
	{
		printf("队列已满");
		return;
	}
	q->data[q->rear] = x;
	q->rear++;
}

代码解释:
首先判断队列是否已满,满了就跳出去;
没有满,就在这个数组的最后一位进行插入,并让rear往后挪一位。


DeQueue函数:

void DeQueue(int*  x)
{
	if(q->rear == q->head)
	{
		printf("队列已空");
		return;
	}
	* x = q->data[q->head];
	q->data[q->head] = NULL;
	q->head++;
}

代码解释:
首先判断队列是否为空,空队列就跳出去;
不是空队列,就在这个数组的第一位一位进行删除,并让head往后挪一位。


完整代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAXSIZE 100

struct Queue
{
	int data[MAXSIZE];
	int head;
	int rear;
};

struct Queue* q;

void Init()
{
	struct Queue* temp = (struct Queue*)malloc(sizeof(struct Queue));
	q = temp;
	free(temp);
	q->head = 0;
	q->rear = 0;
	
}

int IsEmpty()
{
	if (q->head == q->rear)
		return 1;
	return 0;
}

int IsFull()
{
	if (q->rear == MAXSIZE && q->rear != q->head)
		return 1;
	return 0;
}

void EnQueue(int  x)
{
	if (q->rear == MAXSIZE)
	{
		printf("队列已满");
		return;
	}
	q->data[q->rear] = x;
	q->rear++;
}

void DeQueue()
{
	int * x = (int*)malloc(sizeof(int));
	if (q->rear == q->head)
	{
		printf("队列已空");
		return;
	}
	*x = q->data[q->head];
	q->data[q->head] = NULL;
	q->head++;
	free(x);
}

int main()
{
	int i, a;
	Init();
	a = IsEmpty();
	if (a == 1)
		printf_s("队列为空\n");
	else
		printf_s("队列可插入");
	EnQueue(2);
	EnQueue(4);
	EnQueue(6);
	EnQueue(8);
	for(i=q->head ;i<q->rear;i++)
		printf_s("%d ", q->data[i]);
	printf_s("\n");
	DeQueue();
	for (i = q->head; i < q->rear; i++)
		printf_s("%d ", q->data[i]);
}

3.循环队列


可能很多人意识到了上面这个队列有逻辑上的小瑕疵:那就是会有假溢出现象——指数组空间其实未用完,但是我们的 head 和 rear 导致不能在进行输入元素;
下面我说一下解决办法:
求模运算(%):求a/b的余数。


新EnQueue函数:

void EnQueue(int  x)
{
	if (q->rear == MAXSIZE)
	{
		printf("队列已满");
		return;
	}
	q->data[q->rear] = x;
	q->rear = (q->rear+1)%MAXSIZE;
}

新DeQueue函数:

void DeQueue()
{
	int * x = (int*)malloc(sizeof(int));
	if (q->rear == q->head)
	{
		printf("队列已空");
		return;
	}
	*x = q->data[q->head];
	q->data[q->head] = NULL;
	q->head = (q->head+1)%MAXSIZE;
	free(x);
}

4. 用链表实现队列


学习完数组实现队列,接下来学习链表实现队列;


队列的定义和初始化:

struct Node
{
	int data;
	struct Node* next;
};

struct Node* front = NULL;
struct Node* rear = NULL;

Enqueue函数:

void Enqueue(int x)
{
	struct Node*temp = (struct Node*)malloc(sizeof(struct Node*));
	temp->data = x;
	temp->next = NULL;
	if(front == NULL && rear == NULL)
	{
		front = rear =temp;
		return;
	}
	rear->next =temp;
	rear = temp;
}

代码解释:
首先在堆为 temp 开辟内存,为 temp->data 赋值,让 temp->next 指向NULL;
接下来进行判断,如果队列是空队列,那么让 front 和 rear 都指向 temp;
如果队列不为空,那么让 rear->next 指向 temp 指向,这样就把前一个元素和现在这个元素连接上了;
再让 rear = temp ,这样就能为下一次连接做准备。


Dequeue函数()

void Dequeue
{
	struct Node* temp = front;
	if (front == NULL)
		return;
	else if (front == rear)
		front = rear = NULL;
	else
	{
		front = front->next;
	}
	free(temp);
}

代码解释:
这个就很好理解,头删除,我只需要删除队列的第一个元素就ok,然后再让 front 指向下一个,最后释放 temp 指针。


Peek函数:

void Peek()
{
	if (front == rear)
		printf_s("空队列");
	printf_s("%d\n",front->data);
}

Peek函数很容易理解,这里我就不多赘述了。


  • 最后以上内容就是这么多,希望读者多加练习,会很容易了解数据结构的。
    Harsha Suryanarayana的熟肉
    同时也感谢up主fengmuzi2003的翻译。

  • 后续秋秋文章发布的频率不会这么快了,完结数据结构之前,秋秋可能一周发布一到两篇,其中数据结构内容包括:链,栈,队列,二叉树,图,看情况发布一些额外的排序和查找功能。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值