FIFO 队列的链表和数组实现

FIFO (First-in, First-out,先进先出)队列:当执行delete操作时删除那些呆在队列中时间最长的元素。

FIFO 队列是这样一个ADT,包含两个基本操作:插入(put)一个新的项、删除(get)一个最早插入的项。

一、FIFO队列的链表实现

FIFO 队列和下堆栈的区别在于新项的插入是在尾部,而不是在头部。因此实现程序要保存一个指向链表最后一个节点的尾指针tail ,因此当Put操作时,将tail 指针指向的next 指向新节点,然后更新tail指针,让它指向那个新的节点。

FIFO_LinkList.cpp

/*************************************************************
功能:先进先出队列的链表形式实现:Init、Put、Get操作
说明:  从头部Get,从尾部Put
时间: 2015/02/03
作者: quinn
**************************************************************/
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
typedef int Item;
typedef struct Node Node;
typedef Node* Queue;
struct Node //节点结构
{
	Item item;
	Node* next;
};
static int maxN = 10;
static Queue q = NULL;
static Node* tail = NULL;

//新建一个节点
Node* NewNode(Item item, Node* Next) // Next为插入的后一节点
{
	Node* x = (Node*)malloc(sizeof(*x));//被插入的节点
	x->item = item;
	x->next = Next;
	return x;
}

//队列初始化
void QueueInit(int maxN)
{
	q =  NULL;
}

//判断队列是否为空
int QueueIsEmpty()
{
	return (q == NULL);
}

//put操作
void QueuePut( Item item)
{
	if(QueueIsEmpty())
	{
		q = (tail = NewNode(item, q));
	}
	else
	{
		tail->next = NewNode(item, tail->next);
		tail = tail->next;
	}
	printf("Put: %d\n", item);
}

//get操作
Item QueueGet()
{
	if(q == NULL)
	{
		printf("序列为空!\n");
		return -1;
	}

	Item firstItem = q->item;//序列的头元素
	Node* tmpNode = q;
	q = q->next;
	free(tmpNode);
	return firstItem;
}

//测试程序
int main()
{
	QueueInit(maxN);
	QueuePut(2);
	QueuePut(3);
	QueuePut(4);
	printf("\n");
	printf("Get: %d\n", QueueGet());
	printf("Get: %d\n", QueueGet());
	printf("Get: %d\n", QueueGet());
	printf("Get: %d\n", QueueGet());
	system("pause");
	return 0;
}

运行结果:

二、FIFO队列的数组实现

队列中的内容是数组中从head到tail的所有元素,到tail到达数组尾部时回卷到0,此程序的实现过程需要考虑队列满和队列空两种特殊状态,

本文采用2种方式实现:

1)设定FIFO队列的数组大小比客户将在队列放置的元素最大数目大1(From:《算法:C语言实现》P93)

当head和tail重合时为空;当tail+1和head重合时为满

FIFO_Array_1.cpp

/*************************************************************
From:《算法:C语言实现》 P93
功能:先进先出队列的数组形式实现:Init、Put、Get操作
说明:  1)队列中的内容是数组中从head到tail的所有元素,到tail到达数组尾部时回卷到0
	2)设定FIFO队列的数组大小比客户将在队列放置的元素最大数目大1,
	当head和tail重合时为空;当head和tail+1重合时为满
时间: 2015/02/03
作者: quinn
**************************************************************/
#include<stdio.h>
#include <stdlib.h>
const int maxN = 10; //FIFO size
typedef int Item;
static Item *q; //队列
static int head, tail, N;
//队列初始化,初始化数组、头尾索引
void QueueInit(int maxN)
{
	q = (Item*)malloc(sizeof(*q) * (maxN+1));
	N = maxN + 1;
	head = N;
	tail = 0;
}

//检查队列是否为空
int QueueIsEmpty()
{
	return (head % N) == tail;  // Get操作中head++位于%操作之后;Put操作中tail++位于%操作之前
}
int QueueIsFull()
{
		return (tail + 1)%N == head % N;
}
//推入队列,Put操作
void QueuePut(Item item)
{
	if (QueueIsFull())
	{
		printf("队列已满,Put: %d 操作失败\n", item);
		return;
	}
	q[tail++] = item;
	tail %= N;

	printf("Put: %d\n", item);
}
//出队列,Get操作
Item QueueGet()
{
	if (QueueIsEmpty())
	{
		printf("此队列现为空,Get操作失败,返回-1\n");
		return -1;
	}
	head %= N;
	return q[head++];
}

//测试程序
int main()
{
	QueueInit(maxN);
	for (int i = 0; i <= 10; i++)
	{
		QueuePut(i);
	}
	printf("\n");
	printf("Get: %d\n\n", QueueGet());
	for (int i = 0; i < 10; i++)
	{
		printf("Get: %d\n", QueueGet());
	}
	system("pause");
	return 0;
}

运行结果

2)设定FIFO队列的数组大小和客户将在队列放置的元素最大数目相等

当put操作导致tail和head重合时,设定满标志flag_full = 1;(初始化设定flag_full
= 0)

当get操作导致tail和head重合时,设定空标志flag_empty = 1;(初始化设定flag_empty = 1)

FIFO_Array_2.cpp

/*************************************************************
功能:先进先出队列的数组形式实现:Init、Put、Get操作
说明:1)设定FIFO队列的大小,队列中的内容是数组中从head到tail的
			所有元素,到tail到达数组尾部时回卷到0
时间: 2015/02/03
作者: quinn
**************************************************************/
#include<stdio.h>
#include <stdlib.h>
const int maxN = 10; //FIFO size
typedef int Item;
static Item *q;
static int head, tail;
static int flag_full = 0, flag_empty = 1; //队列满空标志
//队列初始化,初始化数组、头尾索引
void QueueInit(int maxN)
{
	printf("初始化FIFO大小为%d\n",maxN);
	q = (Item*)malloc(sizeof(*q) * maxN);
	head = 0;
	tail = 0;
}
//推入队列,Put操作
void QueuePut(Item item)
{
	if (flag_full)
	{
		printf("队列已满,Put:%d 操作失败\n",item);
		return;
	}

	q[tail++] = item;
	tail %= maxN;

	printf("Put: %d\n", item);
	flag_empty = 0; //put后非空
	if (tail  == head)//Put操作导致的head和tail重合时,队列满
	{
		flag_full = 1;
	}

}

//出队列,Get操作
Item QueueGet()
{

	if (flag_empty)
	{
		printf("队列为空,Get操作失败,返回-1\n");
		return -1;
	}

	head %= maxN;

	flag_full = 0; //Get操作成功,满标志设为0
	if ((head+1) % maxN == tail) //Get导致head+1和tail重合,队列空
	{
		flag_empty = 1;
	}

	return q[head++];

}

//测试程序
int main()
{
	QueueInit(maxN);
	for (int i = 0; i <= 10; i++)
	{
		QueuePut(i);
	}
	printf("\n");
	printf("Get: %d\n\n", QueueGet());
	for (int i = 0; i <= 10; i++)
	{
		printf("Get: %d\n", QueueGet());
	}
	system("pause");
	return 0;
}

运行结果:

FIFO队列ADT的get操作和put操作不论使用数组还是链表都能在常数时间内实现。

参考资料:《算法:C语言实现》 P93

时间: 2024-11-20 22:42:16

FIFO 队列的链表和数组实现的相关文章

队列的实现方式(链表和数组)

1 #include <stdio.h> //队列的链表实现方式 2 #include <stdlib.h> 3 #include <stdbool.h> 4 5 6 //队列的声明 7 struct QueueRecord; 8 typedef struct QueueRecord *QueuePtr; 9 typedef struct QueueNode *Queue; 10 typedef int ElementType; 11 12 bool IsEmpty(Q

数组队列 与 链表队列

做了些实验,感觉 用链表实现队列 比 用数组实现队列 性能好 进出队的每秒操作数比较 数组队列 enqueue 37,037 dequeue 4,166,666 链表队列 enqueue 277,778 dequeue 666,667 先入队n次,再出队n次的运行时间比较,单位是秒 出入队次数 | 数组队列运行时间 | 链表队列运行时间 1,000 0.01 0.01 10,000 0.04 0.04 100,000 2.7 0.4 1,000,000 4 最后一组,数组队列的半天没运行出来 下

《啊哈算法》——栈、队列、链表

通过题目我们可以看出这篇文章将介绍什么,栈.队列.链表本质上是数据结构中的东西,通过这章的学习能够给今后数据结构的学习打下一点基础. 队列: 我们通过一个简单的谜题来引入队列的概念,给出一串9位的加密QQ号,对于这串数字,删除第一位数字,然后将第二位数字放到这串数字的最后.反复操作,直到这一串数字的所有数字都被删除.在这个过程中,按照数字删除先后顺序排列的9位数字的便是解密后的QQ号,请问解密后的QQ号是多少? 其实从数学原理的角度,这个问题并没有什么难度,非常好理解,但关键在于,如何通过程序来

算法导论第十章 栈队列和链表

本章讲述的是基本的数据结构,如栈.队列和链表.这些都是最最基本的数据结构,具体的就不再啰嗦.然后本章也没有什么需要特别注意的点,哦,有一个小节:指针和对象的实现,可以认真看一下,大概就是用其他的实现方式来代替指针和对象的实现,因为有些语言不支持指针和对象数据类型,那在实现这种链式的数据结构就无法表示,本节介绍的方法就是利用数组和数组下标来构造对象和指针,说白了,就是利用数组来表示链式对象.个人感觉意义不大,权当了解得了. 结合一些常见的笔试面试题,我就用3个习题来总结这一章吧. 1.习题10.1

抽象数据类型总结:复数 adt 和 FIFO 队列adt

定义:抽象数据类型(abstract data type, ADT)是指"只"通过接口进行访问的数据类型.我们将那些使用ADT的程序叫做客户,将那些确定数据类型的程序叫做实现. 客户程序除了通过接口中提供的那些操作外,并不访问任何数据值.数据的表示和操作都在接口的实现里,和客户完全分离. 数据结构.数据类型和抽象数据类型 数据结构.数据类型和抽象数据类型,这3个术语在字面上虽不同但相近,反映出它们在含义上既有区别又有联系. 数据结构 数据结构是计算机科学与技术领域常用的术语.它用来反映

文件 FIFO队列

<?php /** * Filefifo.php 文件型FIFO队列 */ class Filefifo { /** * $_file_data, 数据文件的路径 */ private $_file_data = ''; /** * $_file_idx, 索引文件的路径 */ private $_file_idx = ''; /** * $_file_idx_bak, 索引备份文件的路径, 防止意外断电等导致索引文件破坏 */ private $_file_idx_bak = ''; /**

洛谷P1160 队列安排 链表

洛谷P1160 队列安排   链表 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <cstdlib> 5 #include <string> 6 #include <algorithm> 7 #include <iomanip> 8 #include <iostream> 9 using namespace std

链表和数组的区别

数组是线性结构,可以直接索引,即要去第i个元素,a[i]即可.链表也是线性结构,要取第i个元素,只需用指针往后遍历i次就可.貌似链表比数组还要麻烦些,而且效率低些. 想到这些相同处中的一些细微的不同处,于是他们的真正不同处渐渐显现了:链表的效率为何比数组低些?先从两者的初始化开始.数组无需初始化,因为数组的元素在内存的栈区,系统自动申请空间.而链表的结点元素在内存的堆区,每个元素须手动申请空间,如malloc.也就是说数组是静态分配内存,而链表是动态分配内存.链表如此麻烦为何还要用链表呢?数组不

队列(二)——队列的链表实现方式

1.队列的单向链表的实现方法 return只可以返回一个值,单向循环链表来实现队列的时候可以只保留一个指针,因为保留rear指针能够很方便的表示出front指针,所以保留rear指针. 另外由于链表的第一个结点处理比较特殊,所以在初始化的时候需要单独处理.链表实现的队列思想也是第一个单元作为头结点,不存放数据,rear指针指向的总是尾结点(在循环链表中也就是头结点的上一个结点). 2.实现方法 用带表头的单向循环链表来实现 #include <stdio.h> #include <mal