2.07——队列

2.07——队列

1. 什么是队列

​ 队列(queue)是只允许在一端进行插入操作,而在另一端进行数据操作的线性表。

​ 队列是一种先进先出(First In First Out)的线性表,简称FIFO。允许插入的一端成为队尾,允许删除的一端成为队头。假设队列是q=(a1, a2, a3, …, an),那么a1就是队头元素,而an是队尾元素。这样我们就可以删除时,再试从a1开始,而插入时,列在最后。

2. 队列的存储结构

​ 线性表有循序存储和链式存储,栈是线性表,所以有这两种存储方式。同样,队列作为一种特殊的线性表,也同样存在着两种存储方式。顺序队列用数组存储,链式队列有链表存储。

3. 队列的顺序存储结构

​ 假设一个队列有n个元素,则顺序存储的队列需建立一个大于n的数组,并把队列的所有元素存储在数组的前n个单元,数组下标为0的一端即是队头。所谓的入队列操作,其实就是在队尾追加一个元素,不需要移动任何元素,因此时间复杂度为O(1)。与栈不同的是,队列元素的出列是在队头,即下标为0的位置,那也就意味着,队列中的所有元素都得向前移动,以保证队列的队头,也就是下标为0的位置不为空,此时时间复杂度为O(n)。

4.什么是队列的假溢出

​ 为了避免当只有一个元素时,对头和队尾重合使初始变得麻烦,所以引入两个指针,front指针指向队头元素,rear指针指向队尾元素的下一个位,这样当front等于rear时,此队列不是还剩一个元素,二十空队列。

​ 假设是长度为5的数组,初始状态,空队列。front与rear指针均指向下标为0的位置。然后入队a1、a2、a3、a4,front指针移入指向下标为0位置,而rear指针指向下标为4的位置。

​ 出队a1、a2,则front指针指向下标为2的位置,rear不变,在入队a5,此时front指针不变,rear指针移动到数组之外。

​ 如果这个队列的总个数不超过5个,但目前如果接着入队的话,因数组末尾元素已经占用,再向后加,就会产生数组越界的错误,可实际上,我们的队列在下标为0和1的地方还是空闲的。我们把这种现象叫做“假溢出”。

5. 循环队列的定义

​ 为了解决假溢出的办法就是后面满了,就从头开始,也就是头尾详解的循环。我们把队列的这种头尾相接的顺序存储结构成为循环队列。如果队列满了,rear就指向下标为0的位置,这样就不会造成指针指向不明的问题了。

6. 队列的链式存储结构

​ 队列的链式存储结构,其实就是线性表的单链表,比不过它只能尾进头出而已,我们把它简称为链队列。为了操作上的方便,我们将队头指针指向链队列的头结点,而队尾指针指向终端结点。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jJKOAx1a-1590541551466)(http://p3glgyim1.bkt.clouddn.com//img/6.png)]

​ 空队列时,front和rear都指向头结点。

typedef int QElemtype;

typedef struct QNode
{
  	QElemType data;
  	struct QNode *next;
}QNode, *QueuePtr;

typedef struct
{
  	QueuePtr front,rear;
}LinkQueue;

7. 链式队列的入队

​ 入队操作时,其实就是在链表的尾部插入结点。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UDf8H9DS-1590541551467)(http://p3glgyim1.bkt.clouddn.com//img/clip1517984231.png)]

其代码如下:

Status EnQueue(LinkQueue *Q, QElemType e)
{
	QueuePtr s =(QueuePtr)malloc(sizeof(QNode));
    if(!s)
    {
      	eixt(OVERFLOW);
    }
    s->data = e;
    s->next = NULL;
    Q->rear-next = s;
 	Q-rear = s;
    
    return OK;
}

8. 链式队列的出队操作

​ 出队操作时,就是头结点的后继结点出队,将头结点的后继改为它后面的结点,若链表出头结点外只剩一个元素时,则需将rear指向头结点。

​ 代码如下:

Status DeQueue(LinkQueue *Q, QElemtype *e)
{
  	QueuePtr p;
  	if (Q->front == Q->rear)
  	{
		return ERROR ;     
  	}
  	p = Q->front->next;
  	*e=p->data;
  	Q->front->next = p->next;
  	
  	if(Q->rear == p)
  	{
		Q->rear = Q->front;      
  	}
  	free(p);
  	
  	return OK;
}

9. 循环队列与链队列的比较

​ 可以从两方面来考虑,从时间上,其实它们的基本操作都是常数时间,即都是为O(1)的,不过循环队列是事先申请号空间,使用期间不是放,而对于链队列,每次申请和方式结点袁辉存在一些时间开销,如果入队和出队频繁,则两者还是有细微差异。对于空间上开说,循环队列必须有一个固定的长度,所以就有了存储元素个数和空间浪费的问题。而链队列不存在这个文件,尽管它需要一个指针域,会产生一些空间上的开销,但也可以接收。所处在空间上,见队列更加灵活。

10. 栈和队列的比较

​ 栈(stack)是限定在表尾进行插入和删除操作的线性表。

​ 队列(queue)是只允许在一端进行插入操作,而在另一端进行数据操作的线性表。

​ 它们均可以用线性表的顺序存储结构来实现,但都存在着顺序存储的一些弊端。因此它们各自有各自的技巧来解决这个问题。

​ 对于栈来说,如果是两个相同数据类型的栈,则可以用数组的两端作栈底的方法来让两个栈共享数据,这就可以最大化地利用数组的空间

​ 对于队列来说,为了避免数组插入和删除时需要移动数据,于是就引入了循环队列,使得队头和队尾在数组中循环变化。解决了移动数据的时间损耗,使得真来插栓换删除是O(n)的时间复杂度变了了O(1)。

​ 它们也都可以通过监视存储结构来实现,实现原则上与线性表基本相同如图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1iHSknC1-1590541551469)(http://p3glgyim1.bkt.clouddn.com//img/clip1517985682.png)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值