队列的实现和基本操作

队列的表示和实现


  <队列是仅在表尾进行插入操作,在表头进行删除操作的线性表;
  <表尾即an端,表头即a1端;(也称作队尾队头)
  <它是一种先进先出的(FIFO)线性表
  <例如Q(a1,a2,a3,......,an),a1为队头,an为队尾;
  <插入元素称作入队,删除元素称作出队;
  <队列的存储结构为顺序队或者链队;

队列的顺序表示

#define MAXQSIZE 1000           //最大的队列长度
Typedef struct{
	QElemType *base;            //初始化队列动态分配存储空间 
	int front;                  //头指针 
	int rear;                   //尾指针 
}SqQueue;

 队列在内存中的存储情况如图1:

 图1 队列在内存中的存储情况 

 这里的front和rear虽然是int类型,但是其功能与指针类似。


 下面简单介绍一下队列的入队:

  front==0且rear==MAXQSIZE;再入队,真溢出;
  front!=0且rear==MAXQSIZE;再入队,假溢出;
  
//解决假溢出的方法
/*<1>将队中元素依次向队头方向移动
(缺点:浪费时间,每移动一次,队中元素都要移动)
  <2>将队空间想象成一个循环表
  即分配给队列的m个存储单元可以循环使用,
  当rear为MAXQSIZE时,若队列的开始端空着,又可以从头使用空着的空间
  当front为MAXSIZE时,若队列的开始端空着,又可以从头使用空着的空间
  <3>引入循环队列*/

  
循环队列的操作


/*

base[0]接在base[MAXQSIZE-1]之后,相当于一个圈
  若rear+1==MAXQSIZE,令rear=0;
  插入元素:Q.base[Q.rear]=x;
            Q.rear=(Q.rear+1)%MAXQSIZE;
  删除元素:x=Q.base[Q.front];
            Q.front=(Q.front+1)%MAXQSIZE;
*/  

循环队列的存储情况如图2所示:

图2 循环队列在内存中的存储情况

Q.rear=(Q.rear+1)%MAXQSIZE;

Q.front=(Q.front+1)%MAXQSIZE;  

因为内存下标是从0开始的,所以要加一

  

 那么循环队列中队空、队满的标志是什么呢?

有没有发现在循环队列中队空、队满的标志都是front==rear;

那么我们该如何区分队空、队满呢?

其实很简单,只需要空出一个元素空间即可,如图3:

图三 空出一个元素空间后的存储情况

队空:front==rear;

队满:(rear+1)%MAXQSIZE==front;

循环队列的操作

队列的初始化(相当建立一个空的队列)

//队列的初始化
Status InitQueue(SqQueue Q){
	Q.base=(QElemType *)malloc(sizeof(QElemType)*MAXQSIZE);
	if(!Q.base){
		return OVERLOW;
	}
	else{
		Q.front=Q.rear=0;           //front和rear相当于指针
		return OK; 
	}
} 
 

求队列长度


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

 

若rear-front<0,那么rear-front的绝对值表示该表中元素个数与MAXQSIZE的差值,即空格个数,

rear-base+MAXQSIZE可以表示该表中元素个数

若rear-front>0,那么rear-front可以直接表示该表中元素个数
  

 循环队列在内存中的几种存储情况如图4所示:

图4 循环队列中的几种存储情况

 

循环队列入队


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

队列入队只在队尾进行,相较于单链表的插入简单很多

但要注意,要判断是否队满

循环队列出队


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

 队列出队只在队头进行

应判断是否队空

取队头元素


SElemType GetHead(SqQueue Q){
	if(Q.front!=Q.rear){              //队列不为空 
		return Q.base[Q.front];
	}
} 

可以直接访问头指针所指向的元素

 //注意:返回的只是队头元素的值,队头指针不变

队列的链式表示和实现

链队列的类型定义


#define MAXQSIZE 100
typedef struct Qnode{
	QElemType data;
	struct Qnode * next;
}QNode,*QueuePtr;

typedef struct{
	QueuePtr front;          //队头指针 
	QueuePtr rear;           //队尾指针 
}LinkQueue; 

这里的front相当于单链表里的头结点

 链队列的初始化


Status InitQueue(LinkQueue Q){
	Q.front=Q.rear=(QueuePtr)malloc(sizeof(QNode));
	Q.front->next=Q.rear->next=NULL;
	return OK;
}
  

相当于建立一个空队

  
链队列的销毁


Status DestoryQueue(LinkQueue Q){
	while(Q.front){
		p=Q.front->next;
		free(Q.front);
		Q.front=p;
	}
	return OK;
} 
 

销毁与单链表类似,表中所有东西都不存在,包括头结点

链队列的入队


Status EnQueue(LinkQueue Q,QElemType e){
	p=(QueuePtr)malloc(sizeof(QNode));
	if(!p){
		return OVERLOW;
	}
	p->data=e;
	p->next=NULL;
	Q.rear->next=p;
	Q.rear=p;
	return OK;
} 

队列只能在队尾入队,相比于单链表,链队多了一个尾指针,所以操作起来很简单

链队列出队


Status DeQueue(LinkQueue Q,QElemType e){
	if(Q.front==Q.rear){
		return ERROR;
		}                 //队空
		QNode * p;
		p=Q.front->next;
		e=p->data;
		Q.front->next=p->next;
		if(Q.rear==p){    //如果队中只有一个元素,删除后需要修改指针 
			Q.rear=Q.front;
		}
        free (p);
		return OK; 
	}
} 
 

队列的出队只能在队头进行,相当于删除用第一个数据元素所在的结点

其详细过程如图5所示:

图5 链队出队过程详解 

取队头元素


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

取队头元素可以直接访问头指针

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值