数据结构学习(六)——循环顺序队列的操作

队列是一种只允许在表的一端(称为队尾)进行插入,而在另一端(称为队头)进行删除的线性表,是线性表的一种特例。

顺序队列是用数组结构来表示的。为了描述队列的这种结构,我们需要两个表明队头和队尾的指针,规定队头指针指向队列头结点的前一个位置,而队尾指针指向队列的尾结点。而为什么又会用到循环队列呢,因为为了防止“假上溢”对空间造成的浪费。“假上溢”是这么来的,先说“上溢”和“下溢”。下溢就是当空对时,如果再做出队操作,则会产生“下溢”。

当队满时,再做入对操作会产生“上溢”。但是,如果当前尾指针等于数组的上界,即使队列不满,再做入队操作也会引起溢出。这种现象就是“假上溢”。然而有了循环队列,我们就可以避免假上溢的问题了。但是循环队列还是有一个问题,就是判断队列与队满的情况。如果按照前面的规定,队头指针指向队列头结点的前一个位置,而队尾指针指向队列的尾结点。那么是分辨不出来队满与队空的关系的。我看书中列出了3种解决此问题的方法。不过第三种最适合,它是采用少用一个节点空间,即头指针指向的空间不使用。这样的话。当front等于rear时,队空;入队后,当尾指针加1后等于头指针,即:(rear+1)%maxsize = front.则说明这时队列已满。

下面是对循环顺序队列操作的一个整体代码:

#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 100

typedef struct node
{
	int data[MAXSIZE];
	int front;			//存放队列头地址
	int rear;			//存放队列尾地址
}sequeue;

void Sequeue_SetNull(sequeue *q);		//队列置空
int Sequeue_Empty(sequeue *q);			//判断队列是否为空
int Sequeue_GetFront(sequeue *q);		//得到队列头结点
int Sequeue_In(sequeue *q, int dat);	//入对操作
int Sequeue_Out(sequeue *q);			//出队操作
void ShowSequeue(sequeue *q);			//输出显示队列

int main(void)
{
	int num, i, dat, choice, ans;
	sequeue *q;

	q = (sequeue*)malloc(sizeof(sequeue));

	printf("循环顺序队列的操作练习:\n");
	printf("输入你想创建队列的数据个数:\n");
	scanf("%d", &num);
	if(num>MAXSIZE-1)
	{
		printf("队列结点数大于最大允许空间!\n");
		return 0;
	}
	Sequeue_SetNull(q);	
	printf("请依次输入队列数据:\n");
	for(i=1; i<num+1; i++)			//循环输入队列结点数据
	{
		scanf("%d", &dat);
		q->data[i] = dat;
		q->rear = i;
	}
	while(1)
	{
		printf("队列操作:\n");
		printf("1.取队列结点\n");
		printf("2.入队操作\n");
		printf("3.出队操作\n");
		printf("4.输出队列\n");
		printf("5.退出程序\n");
		printf("做出选择:\n");
		scanf("%d", &choice);

		switch(choice)
		{
		//取队列头结点
		case 1:
			dat = Sequeue_GetFront(q);
			printf("头结点为:%d\n", dat);
			break;
		//入队
		case 2:
			printf("输入你想入队的数据:\n");
			scanf("%d", &dat);
			ans = Sequeue_In(q, dat);
			if(ans)
				printf("入队成功!\n");
			else
				printf("入队失败!\n");
			break;
		//出队
		case 3:
			ans = Sequeue_Out(q);
			if(ans)
				printf("出队成功!\n");
			else
				printf("出队失败!\n");
			break;
		//输出显示队列
		case 4:
			ShowSequeue(q);
			break;
		//退出程序
		case 5:
			return 0;
			break;
		default:
			printf("选择无效!\n");
			break;
		}
	}
}	

//队列置空
void Sequeue_SetNull(sequeue *q)
{
	q->rear = 0;				//其中数组第一个节点空间不使用(即下标为0数组元素),用作队列满与空的区别
	q->front = 0;					
}

//判断队列是否为空
int Sequeue_Empty(sequeue *q)
{
	if(q->front == q->rear)		//头结点等于尾结点即表示队列为空
		return 1;
	else
		return 0;
}

//取得队列头结点
int Sequeue_GetFront(sequeue *q)
{
	if(Sequeue_Empty(q))		//取头结点先要判断队列是否为空
	{
		printf("队列空!\n");
		return 0;
	}
	else
		return q->data[(q->front+1) % MAXSIZE];
}

//入队
int Sequeue_In(sequeue *q, int dat)
{
	if((q->rear+1)%MAXSIZE == q->front)				//入队先要判断队列是否已经满了
		return 0;
	else
	{
		q->rear = (q->rear+1) % MAXSIZE;			//使用求模运算
		q->data[q->rear]= dat;
		return 1;
	}
}

//出队
int Sequeue_Out(sequeue *q)
{
	if(Sequeue_Empty(q))				//出队先要判断队列是否为空
		return 0;
	else
	{
		q->front = (q->front+1) % MAXSIZE;		//求模运算
		return q->data[q->front];
	}
}

//输出显示队列
void ShowSequeue(sequeue *q)
{
	int i;

	i = q->front+1;
	while(i != q->rear+1)
	{
		printf("%d ", q->data[i]);
		i++;
	}
	printf("\n");
}


你可能感兴趣的:(数据结构学习(六)——循环顺序队列的操作)