循环队列操作之一:循环队列的表示和实现(C语言版本)

26 篇文章 1 订阅

队列(Queue)是一种操作受限的线性表,队列(Queue)只能在表的一端进行插入操作,在另一端进行删除操作。其中,允许插入的一端叫着队尾(tail),允许删除的一端叫做队头(front)。循环队列是对队列的一种改进,它比队列适用的范围更广,例如Linux内核当中的环形缓冲区就是基于循环队列来设计的。本文主要任务是通过C语言来实现一个循环队列的数据结构,以及对循环队列的基本操作。


1、循环队列数据结构的实现

在进行循环队列基本操作实现之前,先要实现一个数据结构来表示循环队列,这个结构的定义如下:

/* 定义循环队列的缓冲区的大小 */
#define	MAX_ITEMS		256

/* 定义循环队列的数据结构体 */
typedef enum {FALSE, TRUE} boolean;
typedef struct
{
	int base[MAX_ITEMS];	// 循环队列的缓冲区
	int front;		// 循环队列的头指针
	int rear;		// 循环队列的尾指针
} Queue;
用这个Queue的结构体来表示循环队列,在这个结构体当中有三个成员变量:base用来表示这个循环队列的数据缓冲区,用它来存储插入到队列中的数据;front和rear是循环队列操作数据缓冲区的指针,通过它们不仅可以操作数据而且也可以来判断队列是否为满或者为空。

2、循环队列的创建和销毁

通过malloc来动态创建一个循环队列,通过free来释放前面动态分配的空间。具体的创建函数实现如下:

/* 创建一个循环队列
 *		返回值 : 返回创建的循环队列的结构体指针
 */
Queue *queue_create(void)
{
	Queue *q = malloc(sizeof(Queue));	// 分配一个队列空间
	if(NULL == q)	// 分配失败
	{
		return NULL;
	}
	else	// 分配成功
	{
		q->front = 0;
		q->rear = 0;
		return q;
	}
}
具体的销毁函数实现如下:

/*	销毁一个循环队列
 *		q : 表示要销毁的循环队列
 */
void queue_destroy(Queue *q)
{
	if(NULL != q)
	{
		free(q);	// 执行销毁操作
	}
}


3、判断循环队列是否为空、是否为满
3.1 判断循环队列为空,如果front=rear则循环队列为空,具体实现如下

/*	判断循环队列是否为空
 *		q : 表示要判断的循环队列
 *		返回值: TRUE为空,FALSE为非空
 */
boolean queue_empty(Queue *q)
{
	if(q->front == q->rear) return TRUE;
	else return FALSE;
}
3.2 判断循环队列为满,如果(rear + 1)%maxsize = front 则循环队列为满,具体实现如下:
/*	判断循环队列是否为满
 *		q : 表示要判断的循环队列
 *		返回值: TRUE表示满,FALSE表示非满
 */
boolean queue_full(Queue *q)
{
	if((q->rear + 1)%MAX_ITEMS == q->front) return TRUE;
	else return FALSE;
}

4、向循环队列中插入、取出元素

向循环队列中插入元素,先将元素插入到循环队列的尾部,然后将循环队列尾部的指针加一,具体实现如下:

/*	向队列尾部插入一个元素
 *		q : 要插入的循环队列
 *		item : 要掺入的元素
 *		返回值: TRUE成功,FALSE失败
 */
boolean queue_rear_insert(Queue *q, int item)
{
	if(queue_full(q)) return FALSE;
	else	// 如果循环队列未满
	{
		// 先将元素插入到循环队列的尾部,然后循环队列尾部的rear指针加一
		q->base[q->rear] = item;
		q->rear = (q->rear + 1)%MAX_ITEMS;
		return TRUE;
	}
}
从循环队列中取出元素,先将循环队列头部的元素取出,然后将头部指针加一,具体的实现如下:

/*	将循环队列头部元素删除
 *		q : 要操作的堆栈
 *		返回值: 成功返回要删除的元素值,为0表示删除失败
 */
int queue_front_delete(Queue *q)
{
	int temp_item;
	
	if(queue_empty(q)) return 0;
	else	// 如果堆栈不为空
	{
		// 先将循环队列头部的元素取出,然后将头部指针加一
		temp_item = q->base[q->front];
		q->front = (q->front + 1)%MAX_ITEMS;
		return temp_item;
	}
}

5、循环队列的其他操作

获取循环队列头部元素,具体实现如下:

/*	获取循环队列头部元素
 *		q : 要操作的循环队列
 *		返回值 : 成功返回元素值,失败则返回0
 */
int queue_get_front(Queue *q)
{
	if(queue_empty(q)) return 0;
	else	// 如果不为空,返回堆栈的值
	{
		return q->base[q->front];
	}
}
将整个循环队列所有元素按照先进先出顺序给打印出来:

/*	打印循环队列的元素
 *		q : 要打印的循环队列
 */
void queue_items_print(Queue *q)
{
	int front = q->front;
	int rear = q->rear;
	
	printf("Queue : ");
	while(!(front == rear))		// 判断是否读取完循环队列中所有元素
	{
		printf("%d ", q->base[front]);
		front = (front + 1)%MAX_ITEMS;
	}
	printf("\n");
}


6、测试

在main函数中编写测试程序,来测试前面实现的循环队列的基本操作:包括创建、销毁循环队列,向循环队列中插入元素,从循环队列中取出元素等,具体的测试代码实现如下:

/* 程序的入口 */
int main(int argc, char *argv[])
{
	Queue *q;
	int a[10];
	int i;

	/* 通过控制台输入10个整形元素 */
	printf("Input 10 numbers :\n");
	for(i = 0; i < 10; i++)
	{
		scanf("%d", &a[i]);
	}

	/* 创建一个循环队列 */
	q = queue_create();
	if(NULL == q)
	{
		printf("queue_create error!\n");
		return -1;
	}

	/* 把这个数组中的元素插入到队列当中 */
	for(i = 0; i < 10; i++)
	{
		queue_rear_insert(q, a[i]);
	}

	printf("*******************************************************\n");

	/* 把循环队列中所有元素都打印出来 */
	queue_items_print(q);

	printf("*******************************************************\n");

	/* 向队列中尾部再插入两个元素 */
	queue_rear_insert(q, 200);
	queue_rear_insert(q, 300);
	queue_items_print(q);

	printf("*******************************************************\n");

	/* 从队列头部删除三个元素 */
	queue_front_delete(q);
	queue_front_delete(q);
	queue_front_delete(q);
	queue_items_print(q);

	printf("*******************************************************\n");

	/* 销毁一个循环队列 */
	queue_destroy(q);
	
	return 0;
}
编译并运行结果如下所示:


附录:所实现的完整的程序代码如下所示

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

/* 定义循环队列的缓冲区的大小 */
#define	MAX_ITEMS		256

/* 定义循环队列的数据结构体 */
typedef enum {FALSE, TRUE} boolean;
typedef struct
{
	int base[MAX_ITEMS];	// 循环队列的缓冲区
	int front;				// 循环队列的头指针
	int rear;				// 循环队列的尾指针
} Queue;

/* 创建一个循环队列
 *		返回值 : 返回创建的循环队列的结构体指针
 */
Queue *queue_create(void)
{
	Queue *q = malloc(sizeof(Queue));	// 分配一个队列空间
	if(NULL == q)	// 分配失败
	{
		return NULL;
	}
	else	// 分配成功
	{
		q->front = 0;
		q->rear = 0;
		return q;
	}
}

/*	销毁一个循环队列
 *		q : 表示要销毁的循环队列
 */
void queue_destroy(Queue *q)
{
	if(NULL != q)
	{
		free(q);	// 执行销毁操作
	}
}

/* 初始化循环队列
 *		q : 要初始化的循环队列
 */
void queue_init(Queue *q)
{
	q->front = 0;
	q->rear = 0;
}

/*	判断循环队列是否为空
 *		q : 表示要判断的循环队列
 *		返回值: TRUE为空,FALSE为非空
 */
boolean queue_empty(Queue *q)
{
	if(q->front == q->rear) return TRUE;
	else return FALSE;
}

/*	判断循环队列是否为满
 *		q : 表示要判断的循环队列
 *		返回值: TRUE表示满,FALSE表示非满
 */
boolean queue_full(Queue *q)
{
	if((q->rear + 1)%MAX_ITEMS == q->front) return TRUE;
	else return FALSE;
}

/*	向队列尾部插入一个元素
 *		q : 要插入的循环队列
 *		item : 要掺入的元素
 *		返回值: TRUE成功,FALSE失败
 */
boolean queue_rear_insert(Queue *q, int item)
{
	if(queue_full(q)) return FALSE;
	else	// 如果循环队列未满
	{
		// 先将元素插入到循环队列的尾部,然后循环队列尾部的rear指针加一
		q->base[q->rear] = item;
		q->rear = (q->rear + 1)%MAX_ITEMS;
		return TRUE;
	}
}

/*	将循环队列头部元素删除
 *		q : 要操作的堆栈
 *		返回值: 成功返回要删除的元素值,为0表示删除失败
 */
int queue_front_delete(Queue *q)
{
	int temp_item;
	
	if(queue_empty(q)) return 0;
	else	// 如果堆栈不为空
	{
		// 先将循环队列头部的元素取出,然后将头部指针加一
		temp_item = q->base[q->front];
		q->front = (q->front + 1)%MAX_ITEMS;
		return temp_item;
	}
}

/*	获取循环队列头部元素
 *		q : 要操作的循环队列
 *		返回值 : 成功返回元素值,失败则返回0
 */
int queue_get_front(Queue *q)
{
	if(queue_empty(q)) return 0;
	else	// 如果不为空,返回堆栈的值
	{
		return q->base[q->front];
	}
}

/*	打印循环队列的元素
 *		q : 要打印的循环队列
 */
void queue_items_print(Queue *q)
{
	int front = q->front;
	int rear = q->rear;
	
	printf("Queue : ");
	while(!(front == rear))		// 判断是否读取完循环队列中所有元素
	{
		printf("%d ", q->base[front]);
		front = (front + 1)%MAX_ITEMS;
	}
	printf("\n");
}


/* 程序的入口 */
int main(int argc, char *argv[])
{
	Queue *q;
	int a[10];
	int i;

	/* 通过控制台输入10个整形元素 */
	printf("Input 10 numbers :\n");
	for(i = 0; i < 10; i++)
	{
		scanf("%d", &a[i]);
	}

	/* 创建一个循环队列 */
	q = queue_create();
	if(NULL == q)
	{
		printf("queue_create error!\n");
		return -1;
	}

	/* 把这个数组中的元素插入到队列当中 */
	for(i = 0; i < 10; i++)
	{
		queue_rear_insert(q, a[i]);
	}

	printf("*******************************************************\n");

	/* 把循环队列中所有元素都打印出来 */
	queue_items_print(q);

	printf("*******************************************************\n");

	/* 向队列中尾部再插入两个元素 */
	queue_rear_insert(q, 200);
	queue_rear_insert(q, 300);
	queue_items_print(q);

	printf("*******************************************************\n");

	/* 从队列头部删除三个元素 */
	queue_front_delete(q);
	queue_front_delete(q);
	queue_front_delete(q);
	queue_items_print(q);

	printf("*******************************************************\n");

	/* 销毁一个循环队列 */
	queue_destroy(q);
	
	return 0;
}

  • 8
    点赞
  • 4
    评论
  • 42
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值