从零开始学数据结构系列之第二章《队》

文章目录


队列简介

​    队列只允许在队列头进行删除操作 ,在队列尾进行插入操作 ,当队列中没有元素时,称为空队列在队列中插入元素称为入队,从队列中删除元素称为出队 。因为队列只允许在尾端插入,在头端删除,所以只有最早进入队列的元素才能最先从队列中删除,即队列有 先进先出 的特点。

  • 队列是一种操作受限的线性表,队列只允许在表的一端进行插入,在表的另一端进行删除。可进行插入的一段称为队尾,可进行删除的一端称为队头。
  • 队列的主要特点就是先进先出。依照存储结构可分为:顺序队和链式队。

队列的特点

  • 队列为一种特殊的线性表,

  • 表的前端(front)进行删除操作,在表的后端(rear)进行插入操作,

  • 进行插入操作的端称为队尾,进行删除操作的端称为队头

  • 队列中没有元素时,称为空队列。

  • 队列的数据元素又称为队列元素

  • 在队列中插入一个队列元素称为入队

  • 从队列中删除一个队列元素称为出队

  • 因为队列只允许在一端插入,在另一端删除,所以只有最早进入队列的元素才能最先从队列中删除,故队列又称为先进先出

顺序队列

​   即仅在队头进行删除在队尾进行插入,可用地址连续的存储单元依次存放队列中的数据,比如数组。队头和队尾的位置是变化的,所以要设置头、尾指针。

​   初始化时的头尾指针,均置为 0。 当头尾指针相等时队列为空或者为满,在非空队列里,头指针始终指向队头元素,尾指针始终指向队尾元素的下一位置。

​   由队列的原理可以将头指针当做读操作,将尾指针当做写操作,即在尾端插入数据就是写入队列,在头端删除数据就是将队列中的数据读出,这样好理解点。

​ 刚开始头指针和尾指针都在同一位置

当队列入队时,尾指针加一,头指针保持不变,a1入队,尾指针rear+1指向下一个地址空间 ,即尾指针始终指向队尾的下一地址,如a4入队后,尾指针rear+1 。

队列出队时,尾指针保持不变,头指针依次加1 ,由先进先出原则,a1先入队,则a1先被读走,然后front+1,指向了 a2,a2删除后,front+1指向了 a3。

a5删除后,头指针和尾指针的指向又相同相等了,即说明队列中的数据 已经全部读走

在顺序队列中,当尾指针已经指向了队列的最后一个位置的下一位置时,如果再有元素入队,就会发生"溢出"此时队列中已经填满了数据,头指针还在开始位置。

顺序队列的 "假溢出" :即队列的存储空间并未填满,却发生了溢出。

比如 rear 现在指向了最后一个位置的下一位置,按照上面所说此时队列已经被填满,如果再有元素入队,就会发生"溢出",但这是在头指针没有移动的前提下,如果之前队列头也删除了一些元素,那么队列头指针经过n次的 +1 之后,会遗留下了很多空地址,但是顺序队列就会认为再有元素入队,就溢出,即出现 "假溢出" 现象,这是不合理的。

其实就是类似与尾插法,和栈的差别可以简单的理解为:

  • 插入方式不同,一个类似与头插法,一个类似于尾插法
  • 弹出方式的话,这两个其实差不多,基本可以用相同的方法实现
c 复制代码
#include <stdio.h>
#include <stdlib.h>


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


Node* initQueue() 
{
	Node* node = (Node*)malloc(sizeof(Node));
	node->data=0;
	node->next=NULL;
	return node;
}

/* 
	插入步骤,类似与尾插法
*/
void enQueue(Node* list, int data) 
{
	Node* node = (Node*)malloc(sizeof(Node));
	
	Node* head = list;
	node->data=data;

	while(list->next)list=list->next;
	node->next=list->next;
	list->next=node;

	head->data++;
}

/* 
	判断数据是否为空
*/
int isEmpty(Node* list) 
{
	if(list->data)
		return 1;
	else
		return 0;
}


/* 
	弹出数据,数据先进先出,后进后出
*/
int deQueue(Node* list) 
{
	int data;
	if(isEmpty(list))
	{
		Node* head = list;
		Node* node = list->next;
		data = node->data;
		list->next=node->next;
		free(node);
		head->data--;
		return data;
	}
	else
		return EOF;
}


void printQueue(Node* Q)
{
	Node* node = Q -> next;
    while (node) 
	{
        printf("%d -> ", node -> data);
        node = node -> next;
    }
    printf("NULL\n");
}


int main() 
{
	Node* Q = initQueue();
    enQueue(Q, 1);
    enQueue(Q, 2);
    enQueue(Q, 3);
    enQueue(Q, 4);
    printQueue(Q);
    printf("dequeue = %d\n", deQueue(Q));
    printf("dequeue = %d\n", deQueue(Q));
    printQueue(Q);
    return 0;
}

往期回顾

1.【第一章】《线性表与顺序表》
2.【第一章】《单链表》
3.【第一章】《单链表的介绍》
4.【第一章】《单链表的基本操作》
5.【第一章】《单链表循环》
6.【第一章】《双链表》
7.【第一章】《双链表循环》
8.【第二章】《栈》

相关推荐
StickToForever2 小时前
第4章 信息系统架构(五)
经验分享·笔记·学习·职场和发展
计算机小白一个4 小时前
蓝桥杯 Java B 组之设计 LRU 缓存
java·算法·蓝桥杯
万事可爱^5 小时前
HDBSCAN:密度自适应的层次聚类算法解析与实践
算法·机器学习·数据挖掘·聚类·hdbscan
李白同学5 小时前
【C语言】结构体内存对齐问题
c语言·开发语言
leegong231116 小时前
学习PostgreSQL专家认证
数据库·学习·postgresql
敲敲敲-敲代码6 小时前
【SQL实验】触发器
数据库·笔记·sql
楼台的春风7 小时前
【MCU驱动开发概述】
c语言·驱动开发·单片机·嵌入式硬件·mcu·自动驾驶·嵌入式
Moonnnn.7 小时前
51单片机学习——动态数码管显示
笔记·嵌入式硬件·学习·51单片机
大数据追光猿7 小时前
Python应用算法之贪心算法理解和实践
大数据·开发语言·人工智能·python·深度学习·算法·贪心算法
Dream it possible!7 小时前
LeetCode 热题 100_在排序数组中查找元素的第一个和最后一个位置(65_34_中等_C++)(二分查找)(一次二分查找+挨个搜索;两次二分查找)
c++·算法·leetcode