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

文章目录


队列简介

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

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

队列的特点

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

  • 表的前端(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.【第二章】《栈》

相关推荐
celeste03103 分钟前
Redis Summary
linux·运维·服务器·redis·笔记
ab1515178 分钟前
3.17二刷基础112 118 完成进阶52
数据结构·算法
美式请加冰14 分钟前
链表的介绍和使用
数据结构·链表
会编程的李较瘦15 分钟前
【C语言程序设计学习】一、C语法基础
c语言·开发语言·学习
zzh08118 分钟前
nginx安全笔记
笔记·nginx·安全
旖-旎27 分钟前
二分查找(1)
c++·算法·二分查找·力扣·双指针
困死,根本不会31 分钟前
【C 语言】指针学习笔记:从底层原理到实战应用
c语言·开发语言·笔记·学习·算法
小范自学编程39 分钟前
算法训练营 Day38 - 动态规划part07
算法·动态规划
自动化和Linux1 小时前
C语言_scanf(),strlen(),size()的特性和各自的区别
c语言·开发语言
努力努力再努力...1 小时前
学习Multipath多路径
学习