数据结构——队列

队列

  • 队列
    • 队列初识
    • 队列的基本操作
    • 队列的存储
      • 链队列——链式映像
      • 循环队列——顺序映像
        • 引入循环
        • 循环队列

队列

队列初识

定义:
队列是限定只能在表的一端进行插入,在表的另一端进行删除的线性表

  • 队尾——允许插入的一端
  • 队头——允许删除的一端

队列的特点:先进先出

队列的基本操作

由于没有定义具体的存储结构,所以这一小节仅仅介绍,下一小节依据具体存储结构实现

  • 队列的初始化:InitQueue(&Q)
    初始条件:队列Q不存在
    操作结果:构造一个空的队列
  • 叛队空的操作:QueueEmpty(Q)
    初始条件:队列Q已存在
    操作结果:若Q为空队列,则返回TRUE,否则返回FALSE
  • 入队操作:EnEmpty(&Q,e)
    初始条件:队列Q已存在
    操作结果:插入元素e为Q的新的队尾元素
  • 出队操作:DeQueue(&Q,&e)
    初始条件:Q为非空队列
    操作结果:删除Q的队头元素,并用e返回其值
  • 读取队头元素:GetHead(Q,&e)
    初始条件:Q为非空队列
    操作结果:用e返回Q的队头元素

队列的存储

链队列——链式映像

链式映像的结点结构定义:

typedef struct QNode {		//结点类型
	QElemType data;
	strcut QNode *next;

}QNode,*QueuePtr;

typedef struct //链队列类型
{
	QueuePtr front;		//队头指针
	QueuePtr rear;		//队尾指针
}LinkQueue;

LinkQueue Q;

为了操作方便我们给链队列添加一个头结点,并令头指针指向头结点

数据结构——队列_第1张图片
构造一个空队列:

Status InitQueue(LinkQueue &Q) {
	//构造一个空队列
	Q.front = Q.rear = (QueuePtr)malloc(sizeof*(QNode));
	if(!Q.front)
		exit(OVERFLOW);	//存储分配失败
	Q.front->next = NULL;
}

销毁链队列:

Status DestroyQueue (LinkQueue &Q) {
	while(Q.front) {
		Q.rear = Q.front->next;
		free(Q.front);
		Q.front = Q.rear;
	}
	return OK;
}

判断队列是否为空:

Status QueueEmpty (LinkQueue Q){ //判队列是否为空 
	return (Q.front==Q.rear);
}

求链队列的队头元素:

status GetHead(LinkQueue Q,QElemType &e) {
	if(Q.front == Q.rear)
		return ERROR;
	e = Q.front->next->data;
	return OK;
}

插入元素e为Q的新的队尾元素:

Status EnQueue(LinkQueue &Q,QELemType e) {
	p = (QueuePtr)malloc(sizeof*(QNode));
	if(!p)
		exit(OVERFLOW);	//存储分配失败
	p->data = e;
	p->next = NULL;

	Q.front->next = p;
	Q.rear = p;
	return OK;
} 

删除队头元素:

Status DeQueue(LinkQueue &Q,QElemType &e) {
	//注意:只有一个结点的情况
	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;
}

循环队列——顺序映像

引入循环

队列的顺序存储结构是使用一维数组实现的

数据结构——队列_第2张图片
存在的问题:

设数组长度为M,则:

  • 当front=0,rear=M时,再有元素入队发生溢出——真溢出
  • 当front不等于0,rear= M时,再有元素队列发生溢出——假溢出

解决方案:

1、 队首固定,每次出队剩余向下移动——浪费时间
2、循环队列:

  • 基本思想:把队列设想成环形,让sq[0]接在sq[M-1]之后,若rear+1 == M,则令rear=0

循环队列

实现:利用模运算
队满队空的条件都是front=rear,怎么区分:

  • 1、另外设置一个标志以区分队满队空

  • 2、少用一个元素空间,此时:

    • 队空:front == rear
    • 队满:(rear+1)%M == front
    • 入队:q [rear] = x; rear = (rear+1)%M;
    • 出队:x = =q[front];front = (front+1) % M;

循环队列的类型定义:

#define MAXQSIZE 100		//最大队列长度

typedef struct {
	QElemType *base;	//动态分配内存空间
	int front;			//头指针 若队列不为空 指向队列头元素
	int rear;			//尾指针,若队列不空 指向队列尾元素的下一个位置
}SqQueue;

构造一个空队列Q:

Status InitQueue(SqQueue &Q) {
	//构造一个空队列Q
	Q.base = (QElemType*)malloc(MAXQSIZE*sizeof(QElemType));
	if(!Q.base)
		exit(OVERFLOW);
	Q.front = Q.rear = 0;
	return OK;
}

插入元素e为Q的新的队尾元素:

Status EnQueue(SqQueue &Q,ElemType e) {
	if((Q.rear+1)%MAXQSIZE == Q.front)
			return ERROR;	//队列满
	Q.base[Q.rear] = e;
	Q.rear = (Q.rear+1)%MAXQSIZE;
	return OK;
}

求循环队列的长度:

int QueueLength(SqQueue Q) {
	return (Q.rear - Q.front + MAXQSIZE)%MAXQSIZE;
}

删除队头元素:

Status DeQueue(SqQueue &Q,QElemType &e) {
	if(Q.rear == Q.front)
		return ERROR;
	e = Q.base[Q.front];
	Q.front = (Q.front+1)%MAXQSIZE;
	return OK;
}

你可能感兴趣的:(数据结构与算法,队列,指针,数据结构,链表)