队列(循环队列,链队,双端队列)总结

本文介绍了队列的基本概念和操作,深入讲解了循环队列,包括循环队列的概念、基本操作、判断队列状态的方法。接着讨论了链队列的特点和操作,最后提到了双端队列的概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1 队列

1.1 队列的概念

1.2 队列的基本操作

2.循环队列

2.1 循环队列概念

注意事项:

2.2 循环队列基本操作 

2.2.1 定义循环队列

2.2.2 初始化

2.2.3 判空

2.2.4 求循环队列的长度

2.2.5 入队

2.2.6 出队

2.2.7 取队头元素

2.3 其他建立方法

2.3.1 不浪费队列最后一个存储空间

2.3.2 队尾指针指向队尾元素

3 链队列

3.1 链队列概念

3.2 链队列的基本操作 

3.2.1 链队列定义

3.2.2 初始化

3.2.3 判空

3.2.4 入队

3.2.5 出队

3.2.6 取队头元素

4 双端队列


1 队列

1.1 队列的概念

像栈一样,队列也是一种线性表。它允许在表的一端插入数据,在另一端删除元素。

插入元素的这一端称之为队尾删除元素的这一端我们称之为队首

队列的特性:

  1. 队尾插入元素,在队首删除元素。
  2. 先进先出(排队一样)

1.2 队列的基本操作

InitQueue(&Q):初始化队列,构造一个空队列Q。
DestroyQueue(&Q):销毁队列。销毁并释放队列Q所占用的内存空间。
EnQueue(&Q,x):入队,若队列Q未满,将x加入,使之成为新的队尾。 
DeQueue(&Q,&x):出队,若队列Q非空,删除队头元素,并用x返回。 
GetHead(Q,&x):读队头元素,若队列Q非空,则将队头元素赋值给x。 其他常用操作:
QueueEmpty(Q):判队列空,若队列Q为空返回true,否则返回false。

2.循环队列

2.1 循环队列概念

 设立两个指针:

一个队首指针front ,指向队首元素

一个队尾指针rear ,指向队尾元素的后一个位置(下一个应该插入的位置)·

  • 注意事项:

1.入队可能会越界?

如果是在普通的队列中,那么插入元素,直接将tail + 1即可,但是可能会出现“假溢出现象”,即队尾满了,队头有空却无法插入,所以采用循环队列。可是在长度为n的循环队列中,元素插入的位置可能是原来队首的位置,这样如果直接用tail + 1就会造成越界。所以我们计算数组下标的时候要进行取模。使用( tail + 1 ) % n。同理,删除元素也是类似。

2.如何判断队列是否为空,队列是否为满呢?

从上面的图可以看出当tail == head的时候,这个是否队列是即可以为空,又可以为满。那么我们不妨将队列最后一个元素的位置空出来,少用一个存储空间。

这样的话当tail == head的时候,队列为空。当队列的tail + 1 == head就认为队列已经满了,因为是循环队列,所以计算tail + 1 == head应该算上偏移量即 ( tail + 1 ) % n = head % n

2.2 循环队列基本操作 

  • 2.2.1 定义循环队列

#define MaxSize 100  //最大队列长度 
typedef int ElemType;//ElemType根据实际情况而定,这里假设为int
typedef struct
{
    ElemType *base;    //初始化动态分配空间
    int  front;
    int  rear;
} SqQueue;
  • 2.2.2 初始化

bool InitQueue(SqQueue &Q)
{
//构造一个空队列
    Q.base=(ElemType *)malloc(MaxSize * sizeof(ElemType));
    if (! Q.base)  
        return false;
    Q.front=Q.rear=0;
    return true;
} //InitQueue
  • 2.2.3 判空

bool EmptyQueue(SqQueue Q)//判队空
{
    if(Q.front==Q.rear)
        return true;
    else
        return false;
}
  • 2.2.4 求循环队列的长度

int QueueLength(SqQueue &Q)
{
	return (Q.rear+MaxSize-Q.front)%MaxSize;
}
  • 2.2.5 入队

bool EnQueue(SqQueue &Q,ElemType e)
{
//插入元素e为Q的新的队尾元素
    if ((Q.rear+1)%MaxSize==Q.front)//判断队列有没有满
        return false;
    Q.base[Q.rear]=e;
    Q.rear=(Q.rear+1)%MaxSize;
}
  • 2.2.6 出队

bool DeQueue(SqQueue &Q,ElemType &e)
{// 删除Q的队头元素,并用e返回其值
 
    if(Q.front==Q.rear)
        return false;
    e=Q.base[Q.front];
    Q.front=(Q.front+1) % MaxSize;
}
 
  • 2.2.7 取队头元素

bool GetHead(SqQueue Q,ElemType &e)
{
	if(Q.rear==Q.front)
		return false;
	e=Q.base[Q.front];
    return true;
}

2.3 其他建立方法

2.3.1 不浪费队列最后一个存储空间

 队列元素个数=(rear+MaxSize-front+1)%MaxSize

2.3.2 队尾指针指向队尾元素

初始化时rear=MaxSize-1;

若牺牲队列最后一个存储空间:

  • 判空:(Q.rear+1)%MaxSize==Q.front
  • 判满:(Q.rear+2)%MaxSize==Q.front

若不浪费队列最后一个存储空间,增加辅助变量判断是满是空,同上

队列

3.1 链队列概念

队列的链式存储结构,其实就是线性表的单链表

只不过它只能尾进头出而已,我们把它简称为链队列

注意队列next指针的指向,与链栈不同: 
如果插入一个元素,栈末尾的next指针是指向前一个已经在栈中的元素的 
而队列则是,插入一个元素,其next指针是往外指,指向空。 

同样分为带头结点和不带头结点

带头结点:

  • 队头指针指向链队列的头结点(链队列front没有值,而循环队列的front是有值的)
  • 队尾指针指向队尾结点
  • 当队列为空时,front和rear都指向头结点。

这里写图片描述

不带头结点:

  • 队头指针指向队首结点
  • 队尾指针指向队尾结点
  • 当队列为空时,front和rear都指向NULL。

链队列示意图:

3.2 链队列的基本操作 

  • 3.2.1 链队列定义

///队列
typedef struct QNode
{
    ElemType data;
	struct QNode *next;
}QNode,*QueuePtr;
 
typedef struct
{
    QueuePtr Front;///队头指针
    QueuePtr Rear;///队尾指针
}LinkQueue;
  • 3.2.2 初始化

//1.带头结点
bool InitQueue(LinkQueue &Q)
{
    Q.Front=Q.Rear=(QNode *)malloc(sizeof(QNode));///生成新结点作为头结点,队头和队尾指针指向此结点
    if(!Q.Front)
        return false;
    Q.Front->next=NULL;///头结点的指针域置空
    return true;
}

//2.不带头结点
bool InitQueue(LinkQueue &Q)
{
    Q.Front=NULL;//指针域置空
    Q.Rear=NULL;
    return true;
}
  • 3.2.3 判空

//1.带头结点
bool QueueEmpty(LinkQueue Q)
{
    if(Q.Front==Q.Rear)
        return true;
    else
        return false;
}

//2.不带头结点 
bool QueueEmpty(LinkQueue Q)
{
    if(Q.Front==NULL)
        return true;
    else
        return false;
}
  • 3.2.4 入队

//1.带头结点
void EnQueue(LinkQueue &Q,ElemType e)
{
    QNode *s=(QNode *)malloc(sizeof(QNode));
    s->data=e;
    s->next=NULL;
    Q.Rear->next=s;///将新结点插入到队尾
    Q.Rear=s;///修改队尾指针
}

//2.不带头结点
void EnQueue(LinkQueue &Q,ElemType e)
{
    QNode *s=(QNode *)malloc(sizeof(QNode));
    s->data=e;
    s->next=NULL;
    if(Q.Rear==NULL)//在空队列插入第一个元素
    {
        Q.Front=s;
        Q.Rear=s;
    }
    else
    {
        Q.Rear->next=s;///将新结点插入到队尾
        Q.Rear=s;///修改队尾指针
    }
}
  • 3.2.5 出队

//1.带头结点
bool DeQueue(LinkQueue &Q,ElemType &e)
{
	if(Q.Front==Q.Rear)
		return false;
    QNode *p=Q.Front->next;	//p指向队头
    e=p->data;//回收	
	Q.Front->next=p->next;		
	if(Q.Rear==p)
		Q.Rear=Q.Front;		//最后一个元素被删,队尾指针指向头结点
	free(p);
    return true;
}

//2.不带头结点
bool DeQueue(LinkQueue &Q,ElemType &e)
{
	if(Q.Front==NULL)
		return false;
    QNode *p=Q.Front;	//p指向队头
    e=p->data;//回收	
	Q.Front=p->next;		
	if(Q.Rear==p)
    {
	    Q.Front=NULL;	
	    Q.Rear=NULL;	//最后一个元素被删,队头队尾指针指向NULL
	}
    free(p);
    return true;
}
  • 3.2.6 取队头元素

//1.带头结点
bool GetHead(LinkQueue Q,ElemType &e)
{
	if(Q.Rear==Q.Front)
		return false;
	e=Q.front->next->data;
    return true;
}
//2.不带头结点
bool GetHead(LinkQueue Q,ElemType &e)
{
	if(Q.Front==NULL)
		return false;
	e=Q.front->data;
    return true;
}

4 双端队列

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值