数据结构(超详细讲解!!)第十五节 队列(循环队列)

1.定义

队列是一种先进先出(FIFO, First In First Out)的线性表。

队列是只允许在一端删除,在另一端插入的线性表。

允许删除的一端叫做队头(front), 允许插入的一端叫做队尾(rear)。

数据结构(超详细讲解!!)第十五节 队列(循环队列)_第1张图片

队列的抽象数据类型:

ADT Queue
{	数据对象:D = { ai | ai∈ElemSet, i = 1, 2, …, n, n ≥ 0 }
	数据关系:R = {  | ai-1, ai ∈D, i = 1, 2, …, n }
	基本操作:
		Queue * Init_Queue()
			初始条件:队列Q不存在;
			操作结果:构造一个空的队列Q;
		void Destory_Queue(Queue *Q)
			初始条件:队列Q已经存在;
			操作结果:销毁队列Q;
		Queue * Clear_Queue(Queue *Q)
			初始条件:队列Q已经存在;
			操作结果:将队列Q置为空;
   		……
}

2.队列的顺序表示和实现—循环队列

 在队列的顺序存储中,用一组地址连续的存储单元即数组,依次存放从队头到队尾的数据元素,称为顺序队列。            

根据队列的存储特性,需要附设两个指针:            

1)队头指针front(头指针)指向队头数据元素在队列中的位置。            

2)队尾指针rear(尾指针)指向队尾数据元素在队列中的位置。

1.类型定义

#define  MAXSIZE  1024	/*顺序队列可能的最大长度,假设为1024*/
typedef  int  elemtype;	/* elemtype可为任意类型,假设为int*/
typedef  struct  SequenQueue
{	elemtype  data[MAXSIZE];	/*定义顺序队列为一维数组*/
	int  front;			/*front为头指针*/
	int  rear;			/*rear为尾指针*/
}SequenQueue;			/*顺序队列的结构类型*/

SequenQueue *Q;

Q = (SequenQueue *)malloc(sizeof(SequenQueue));

头、尾指针和顺序队列中数据元素之间的关系:

数据结构(超详细讲解!!)第十五节 队列(循环队列)_第2张图片进队时队尾指针先将新元素按 rear 指示位置加入,再将        rear = rear + 1 。      

出队时队头指针先将下标为 front 的元素取出 ,再将        front = front + 1 。      

队满时再进队将上溢出出错;队空时再出队将下溢出出错。

队列长度:(Q->rear)-(Q->front)

队列空:Q->rear = Q->front

队列满:(Q->rear)-(Q->front)= MAXSIZE

假上溢: Q->rear = MAXSIZE

 顺序队列中尾指针已经达到队列的最大长度,从而不能插入。而此时,实际队列所用的存储空间并没有真正的“被占满”,这种现象就叫做“假溢出”。这是由队列的“队尾入,队头出” 操作造成的 。

一个较巧妙的办法是将顺序队列的数组看成一个头尾相接的循环结构,称为循环队列。

数据结构(超详细讲解!!)第十五节 队列(循环队列)_第3张图片

入队和出队可以通过取模运算来实现指针的循环变化。        

出队:Q.front = ( Q.front + 1 ) % MAXSIZE;        

入队:Q.rear = ( Q.rear + 1 ) % MAXSIZE;

数据结构(超详细讲解!!)第十五节 队列(循环队列)_第4张图片

设MAXSIZE=10,循环队列操作示意图。

数据结构(超详细讲解!!)第十五节 队列(循环队列)_第5张图片

队头指针进1:   Q->front = (Q-> front + 1) % MAXSIZE;

队尾指针进1:  Q-> rear = (Q-> rear + 1) % MAXSIZE;    

队列初始化:  Q-> front = Q-> rear = 0;

队空条件:     Q-> front == Q-> rear;

队满条件: (Q-> rear+1)%MAXSIZE== Q-> front ;

队长:        (Q-> rear- Q-> front + MAXSIZE)% MAXSIZE;

2.基本操作

1.初始化

//循环队列的初始化
SequenQueue * Init_SequenQueue( )
{	SequenQueue *Q;	/*定义循环队列指针变量*/
	Q = (SequenQueue *) malloc ( sizeof( SequenQueue ) );
 	Q->front = 0;		/*设置循环队列的头指针*/
 	Q->rear = 0;		/*设置循环队列的尾指针*/
 	printf("初始化成功。\n");
	return Q;		/*返回循环队列的首地址*/
}

2.判队空

//判队列空
int SequenQueue_Empty(SequenQueue *Q)
{	if ( Q->front == Q->rear )	/*检查队列顶头、尾指针的值*/
	{	printf("队列为空。\n");
	return 1; 	/*队列Q为空,函数返回1*/	}
	else 
	{	printf("队列不为空。\n");
	return 0; 	/*队列Q为不空,函数返回0*/	}
}

3.判队满

//判队列满
int SequenQueue_Full(SequenQueue *Q)
{	if ( (Q->rear+1) % MAXSIZE == Q->front )
	{	printf("队列已满。\n");
	return 1; 			} 
	else
	{	printf("队列未满。\n");
	return 0; 			}
}

4.求队长

//求循环队列的长度
int SequenQueue_Length (SequenQueue *Q)
{	printf("循环队列长度为:%d\n",(Q->rear- Q->front+ MAXSIZE) % MAXSIZE);
      return 1;
}

5.入队

//入队
int Enter_SequenQueue(SequenQueue *Q)/*数据元素x入队*/
{elemtype x;
printf("请输入入队元素:");
scanf(" %d",&x); 
while(x!=0)
{
	if ((Q->rear+1) % MAXSIZE == Q->front)		/*检查队列是否已满*/
	{	printf("队列已满,入队失败。\n");
              return 0; 		/*队满,入队失败,函数返回0*/
	}	
	Q->data[Q->rear] = x;	/*在队列中插入x */
	Q->rear = (Q->rear + 1) % MAXSIZE;  /*将队列尾指针加1*/
	scanf(" %d",&x);
}
printf("入队完成。\n");
	return 1;			/*入队成功,函数返回1*/
}

6.出队

//出队
int  Delete_SequenQueue(SequenQueue  *Q )/*队头数据元素出队,并通过x返回其值*/
{	elemtype x;
if (Q-> front == Q->rear)	/*检查循环队列的长度*/
	{	printf("队列为空,无法出队。\n");
		return 0; 		/*队空,出队失败,函数返回0*/
	} 
	else
	{	x = Q->data[Q-> front];	 /*将原队列的队头数据元素赋值给x*/
		Q-> front = (Q-> front + 1) % MAXSIZE;	/*修改头指针front */
		printf("出队元素为:%d\n",x);
		return 1;		/*出队成功,函数返回1*/
	}
}

7.取队头元素

//取队头数据元素
int  GetFront_SequenQueue(SequenQueue  *Q )/*取队头数据元素,并通过x返回其值*/
{elemtype x;
	if (Q-> front == Q->rear)	/*检查循环队列的长度*/
	{	printf("队列为空。\n");
		return 0; 		/*队空,取数失败,函数返回0*/
	} 
	else
	{	x = Q->data[Q-> front];/*将队头数据元素赋值给x*/
    printf("查看队头元素:%d\n",x); 
		return 1;	/*取数成功,函数返回1*/
	}
}

8.遍历



void Printf(SequenQueue  *Q)
{int i;
for(i=Q->front;i<=Q->rear;i++)
{printf("%d ",Q->data[i]);
}
printf("\n");
}

3.应用

#include
#include


#define  MAXSIZE  1024	/*顺序队列可能的最大长度,假设为1024*/
typedef  int  elemtype;	/* elemtype可为任意类型,假设为int*/
typedef  struct  SequenQueue
{	elemtype  data[MAXSIZE];	/*定义顺序队列为一维数组*/
	int  front;			/*front为头指针*/
	int  rear;			/*rear为尾指针*/
}SequenQueue;			/*顺序队列的结构类型*/

//循环队列的初始化
SequenQueue * Init_SequenQueue( )
{	SequenQueue *Q;	/*定义循环队列指针变量*/
	Q = (SequenQueue *) malloc ( sizeof( SequenQueue ) );
 	Q->front = 0;		/*设置循环队列的头指针*/
 	Q->rear = 0;		/*设置循环队列的尾指针*/
 	printf("初始化成功。\n");
	return Q;		/*返回循环队列的首地址*/
}


//判队列空
int SequenQueue_Empty(SequenQueue *Q)
{	if ( Q->front == Q->rear )	/*检查队列顶头、尾指针的值*/
	{	printf("队列为空。\n");
	return 1; 	/*队列Q为空,函数返回1*/	}
	else 
	{	printf("队列不为空。\n");
	return 0; 	/*队列Q为不空,函数返回0*/	}
}

//判队列满
int SequenQueue_Full(SequenQueue *Q)
{	if ( (Q->rear+1) % MAXSIZE == Q->front )
	{	printf("队列已满。\n");
	return 1; 			} 
	else
	{	printf("队列未满。\n");
	return 0; 			}
}
//求循环队列的长度
int SequenQueue_Length (SequenQueue *Q)
{	printf("循环队列长度为:%d\n",(Q->rear- Q->front+ MAXSIZE) % MAXSIZE);
      return 1;
}

//入队
int Enter_SequenQueue(SequenQueue *Q)/*数据元素x入队*/
{elemtype x;
printf("请输入入队元素:");
scanf(" %d",&x); 
while(x!=0)
{
	if ((Q->rear+1) % MAXSIZE == Q->front)		/*检查队列是否已满*/
	{	printf("队列已满,入队失败。\n");
              return 0; 		/*队满,入队失败,函数返回0*/
	}	
	Q->data[Q->rear] = x;	/*在队列中插入x */
	Q->rear = (Q->rear + 1) % MAXSIZE;  /*将队列尾指针加1*/
	scanf(" %d",&x);
}
printf("入队完成。\n");
	return 1;			/*入队成功,函数返回1*/
}

//出队
int  Delete_SequenQueue(SequenQueue  *Q )/*队头数据元素出队,并通过x返回其值*/
{	elemtype x;
if (Q-> front == Q->rear)	/*检查循环队列的长度*/
	{	printf("队列为空,无法出队。\n");
		return 0; 		/*队空,出队失败,函数返回0*/
	} 
	else
	{	x = Q->data[Q-> front];	 /*将原队列的队头数据元素赋值给x*/
		Q-> front = (Q-> front + 1) % MAXSIZE;	/*修改头指针front */
		printf("出队元素为:%d\n",x);
		return 1;		/*出队成功,函数返回1*/
	}
}

//取队头数据元素
int  GetFront_SequenQueue(SequenQueue  *Q )/*取队头数据元素,并通过x返回其值*/
{elemtype x;
	if (Q-> front == Q->rear)	/*检查循环队列的长度*/
	{	printf("队列为空。\n");
		return 0; 		/*队空,取数失败,函数返回0*/
	} 
	else
	{	x = Q->data[Q-> front];/*将队头数据元素赋值给x*/
    printf("查看队头元素:%d\n",x); 
		return 1;	/*取数成功,函数返回1*/
	}
}

void Printf(SequenQueue  *Q)
{int i;
for(i=Q->front;i<=Q->rear;i++)
{printf("%d ",Q->data[i]);
}
printf("\n");
}



 void menu()
{
printf("--------1.初始化循环队列-----\n"); 
printf("--------2.入队列-------------\n"); 
printf("--------3.出队列-------------\n"); 
printf("--------4.判队列是否为空-----\n"); 
printf("--------5.判队列是否已满-----\n"); 
printf("--------6.查看队头元素-------\n"); 
printf("--------7.遍历---------------\n"); 
printf("--------8.队列长度-----------\n"); 
printf("--------9.退出程序-----------\n");
}

int main()
{SequenQueue *Q;
int n1,n2,n3,n4,n5,n6,a,quit=0;
menu();
while(1)
{
scanf("%d",&a);
switch(a)
{
case 1:Q=Init_SequenQueue( );break;
case 2:n1=Enter_SequenQueue(Q) ;break;
case 3:n2=Delete_SequenQueue(Q);break;
case 4:n3=SequenQueue_Empty(Q);break;
case 5:n4=SequenQueue_Full(Q);break;
case 6:n5=GetFront_SequenQueue(Q);break;
case 7:Printf(Q);break;
case 8:n6=SequenQueue_Length (Q);break;
case 9:quit=1;break;
default:printf("输入1~9之间的数字\n");break;
}
if(quit==1)
{break;
}
}
return 0;
 } 



数据结构(超详细讲解!!)第十五节 队列(循环队列)_第6张图片

你可能感兴趣的:(数据结构(超详细讲解!!),数据结构)