文章目录
- Queue.h
- main.c
- Queue.c
 
用队列实现一个图书信息管理,这里放一下有哪些文件。(ps:我之前写的是学生信息管理,但是有人说我们的作业是写图书,就该了下内容,没有改文件名)
队列是用链表实现的,因为涉及到队列的一些特性,选择链表比数组会更优。
 
 
Queue.h
  #pragma once防止库函数的重复引用,因为库函数会在预编译的时候在程序中展开,会增大程序的体积。
   通过typedef对数据重命名,之后需要修改数据就十分方便。并且其他函数不需要太多的改动。
   这里结构体传的是指针,减少没必要的内存消耗。
   队列的特性是先进先出所以和栈一样只有进出队列,不存在头插尾插、头删尾删的问题。
   这里的图书价格应该使用浮点数类型更合适,只是我之前写的是学生信息管理,不想改了,就这样吧,意思get就行。
#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef struct {
	char name[20];
	char author[20];
	int bno;
	int price;
}QDataType;
typedef struct QListNode
{
	struct QListNode* next;
	QDataType data;
}QNode;
//队列的结构
typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Queue;
//初始化队列
void QueueInit(Queue* q);
//打印
void QueuePrint(Queue* q);
//队尾入队列
void QueuePush(Queue* q, QDataType* data);
//队头出队列
void QueuePop(Queue* q);
//获取队列头部元素 
QDataType* QueueFront(Queue* q);
//获取队列队尾元素
QDataType* QueueBack(Queue* q);
//获取队列中有效元素个数
int QueueSize(Queue* q);
//检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(Queue* q);
//销毁队列
void QueueDestroy(Queue* q);
main.c
因为重点在于数据结构队列的使用,所以直接给定一些数据,就不进行重复繁琐的数据输入工作了。
#define _CRT_SECURE_NO_WARNINGS 1
#include "Queue.h"
void test()
{
	Queue q;
	QueueInit(&q);
	QDataType book1 = { "活着", "余华", 110701, 22 };
	QDataType book2 = { "人血馒头", "余华", 110702, 21 };
	QDataType book3 = { "人间词话", "王国维", 110703, 23 };
	QDataType book4 = { "小词大雅", "叶嘉莹", 110704, 22 };
	QDataType book5 = { "且听风吟", "村上春树", 110705, 23 };
	QueuePush(&q, &book1);
	QueuePush(&q, &book2);
	QueuePush(&q, &book3);
	QueuePush(&q, &book4);
	QueuePush(&q, &book5);
	QueuePrint(&q);
	printf("%d\n\n", QueueSize(&q));
	QDataType* head = QueueFront(&q);
	printf("%s %d %s %d\n\n", head->name, head->bno, head->author, head->price);
	QDataType* tail = QueueBack(&q);
	printf("%s %d %s %d\n\n", tail->name, tail->bno, tail->author, tail->price);
	QueuePop(&q);
	QueuePop(&q);
	QueuePop(&q);
	QueuePrint(&q);
	printf("%d\n", QueueSize(&q));
	QueueDestroy(&q);
}
int main()
{
	test();
	return 0;
}
Queue.c
打印函数的实现,如果队列中的数据类型发生了改变,其他功能函数基本上不需要有什么变化, 打印函数对应修改一下就行了,因为打印需要涉及到具体的数据问题。
void QueuePrint(Queue* q)
{
	QNode* next = q->head;
	while(next != NULL)
	{
		printf("%s %d %s %d\n", next->data.name, next->data.bno, next->data.author, next->data.price);
		next = next->next;
	}
	printf("\n");
}
队列的初始化,将头尾指针都置为NULL,size置为0。
//队列初始化
void QueueInit(Queue* q)
{
	q->head = NULL;
	q->tail = NULL;
	q->size = 0;
}
入队列的实现,先要创建一个节点来存放数据,然后把这个队列插入到队尾。如果这个队列的队尾指针为空,就说明这个队列中并没有数据,那么这个新插入的数据就既是队首又是队尾。如果队列的队尾指针有值,就把新节点插入到当前队尾之后,然后再把队尾指针向后移动一位。插入数据之后要将size加一。
void QueuePush(Queue* q, QDataType* x)
{
	assert(q);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	newnode->data = *x;
	newnode->next = NULL;
	if (q->tail == NULL)
	{
		q->head = q->tail = newnode;
	}
	else
	{
		q->tail->next = newnode;
		q->tail = newnode;
	}
	q->size++;
}
出队列的实现。因为节点是动态开辟的空间,所以出队列之后,要将这个节点的空间释放掉。队列的特性是先入先出,所以,出队列就是删除头结点。删除头结点之前要保存第二个节点的位置,然后删除掉头结点,把第二个节点作为头结点返回。删除数据之后,要将size减一。
void QueuePop(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));
	if (q->head->next == NULL)
	{
		free(q->head);
		q->head = q->tail = NULL;
		q->size--;
	}
	else
	{
		QNode* del = q->head;
		q->head = q->head->next;
		q->size--;
		free(del);
	}
}
获取队列头部元素,这里返回的是一个结构体指针,还是为了减少空间的使用,因为队列本身就具备头指针,所以获取队列头部元素就十分简单。
QDataType* QueueFront(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));
	return &(q->head->data);
}
获取队列队尾元素,一样返回的是一个结构体指针,实现和获取头部元素基本一样。
QDataType* QueueBack(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));
	return &(q->tail->data);
}
获取队列元素个数,不要太简单,本身就有个size,直接返回size就行。
int QueueSize(Queue* q)
{
	assert(q);
	return q->size;
}
检测队列是否为空,如果为空返回非零结果,如果非空返回0。当首尾指针都为空时,队列中就必然没有数据。
int QueueEmpty(Queue* q)
{
	assert(q);
	return q->head == NULL && q->tail == NULL;
}
队列的销毁,因为空间是动态开辟的,所以需要释放空间,如果不释放空间会造成内存泄露。逐一将队列中的节点空间释放掉,最后head和tail的next指针都为NULL,也不需要我们手动置为NULL了。
void QueueDestroy(Queue* q)
{
	assert(q);
	while (q->head)
	{
		QNode* next = q->head;
		q->head = q->head->next;
		free(next);
	}
}



















