C语言数据结构五:队列

队列:就是排队,先进先出

所以从数据流入流出来看,就是对数据的两头(两端)进行操作:一端入队,一端出队。

所以,最佳方式是在对两头位置,用指针进行一个记录。

我们用哪种方式实现?

首先否定栈,因为栈先入后出,且就一个头(一端)

然后看数组,假如出队列放在数组头,入队列放在数组尾,感觉挺合适的,有前有后。但是有个问题,只要是涉及到数组头部的操作。就会导致整个数组下标的改变。

所以我们考虑一下链表。如果链表中,前面我们只关注链表头结点,现在只要关注尾结点,就可以对整个队列实现操作。入队列就操作尾结点,出队列就操作头结点。

所以这个链表跟前面的链表不同点在于,前面链表只有一个头结点,现在我们要加上尾结点。

先写结点数据结构体,然后是链表结构体。增加一个对队列的数量属性。

#pragma once

struct BiNode
{
	int data;
	struct BiNode *lchild;
	struct BiNode *rchild;
};


#include<stdlib.h>

//链表结点的数据类型
struct QueueNode
{
	struct QueueNode *next;
};

//链表数据类型
struct LQueue
{
	struct QueueNode header; //头结点
	int size;
	struct QueueNode *rear; //尾指针,始终指向链表的最后一个节点
};

typedef void* LinkQueue;


#ifdef __cplusplus
extern "C"{
#endif

	//初始化
	LinkQueue Init_LinkQueue();
	//入队
	void Push_LinkQueue(LinkQueue queue, void *data);
	//出队
	void Pop_LinkQueue(LinkQueue queue);
	//获得队头元素
	void* Front_LinkQueue(LinkQueue queue);
	//获得队尾元素
	void* Back_LinkQueue(LinkQueue queue);
	//大小
	int Size_LinkQueue(LinkQueue queue);
	//销毁队列
	void Destroy_LinkQueue(LinkQueue queue);

#ifdef __cplusplus
}
#endif

队列也不支持遍历和随机存取。谁限制的?是上面的接口限制的,上面只提供了必须要的接口,如果先增加,必须修改接口。

初始化:就是在内存中开辟地址,然后给内存中的字段赋初始值。

销毁就是:把你开辟的内存释放掉,然后把字段重新赋值。为空。

实现如下:

#include"LinkQueue.h"


//初始化:就是在内存中开辟地址,给内存字段赋值。
LinkQueue Init_LinkQueue()
{
	struct LQueue *queue = malloc(sizeof(struct LQueue));
	if (NULL == queue)
	{
		return NULL;
	}

	queue->header.next = NULL;
	queue->size = 0;
	queue->rear = &(queue->header);  // 这个初始化为指针只要指向头

	return queue;
}
//入队
void Push_LinkQueue(LinkQueue queue, void *data)
{
	if (NULL == queue)
	{
		return;
	}

	if (NULL == data)
	{
		return;
	}


	struct LQueue *q = (struct LQueue *)queue;
	struct QueueNode *n = (struct QueueNode *)data;

	q->rear->next = n;
	n->next = NULL;
	//更新尾指针
	q->rear = n;

	q->size++;

}
//出队
void Pop_LinkQueue(LinkQueue queue)
{
	if(NULL == queue)
	{
		return;
	}


	struct LQueue *q = (struct LQueue *)queue;
	
	if (q->size == 0)
	{
		return;
	}

	if (q->size == 1)
	{

		q->header.next = NULL;
		q->rear = &(q->header);
		q->size--;

		return;
	}

	struct QueueNode *pFirstNode = q->header.next;

	q->header.next = pFirstNode->next;

	q->size--;

}
//获得队头元素
void* Front_LinkQueue(LinkQueue queue)
{
	if (NULL == queue)
	{
		return NULL;
	}

	struct LQueue *q = (struct LQueue *)queue;

	return q->header.next;
}
//获得队尾元素
void* Back_LinkQueue(LinkQueue queue)
{
	if (NULL == queue)
	{
		return NULL;
	}

	struct LQueue *q = (struct LQueue *)queue;

	return q->rear;
}
//大小
int Size_LinkQueue(LinkQueue queue)
{
	if (NULL == queue)
	{
		return -1;
	}

	struct LQueue *q = (struct LQueue *)queue;

	return q->size;
}
//销毁队列:销毁就是把你开辟的内存释放掉,把赋值的字段重新赋值为空。
void Destroy_LinkQueue(LinkQueue queue)
{
	if (NULL == queue)
	{
		return;
	}

	struct LQueue *q = (struct LQueue *)queue;
	q->header.next = NULL;
	q->rear = NULL;
	q->size = 0;

	free(queue);
	queue = NULL;
}

测试:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include"LinkQueue.h"

struct Person
{
	struct QueueNode node;
	char name[64];
	int age;
};

void test()
{
	//初始化队列
	LinkQueue queue = Init_LinkQueue();

	//创建数据
	struct Person p1 = { NULL, "aaa", 10 };
	struct Person p2 = { NULL, "bbb", 20 };
	struct Person p3 = { NULL, "ccc", 30 };
	struct Person p4 = { NULL, "ddd", 40 };
	struct Person p5 = { NULL, "eee", 50 };
	struct Person p6 = { NULL, "fff", 60 };

	//插入队列
	Push_LinkQueue(queue, &p1);
	Push_LinkQueue(queue, &p2);
	Push_LinkQueue(queue, &p3);
	Push_LinkQueue(queue, &p4);
	Push_LinkQueue(queue, &p5);
	Push_LinkQueue(queue, &p6);


	struct Person *pBack = (struct Person *)Back_LinkQueue(queue);
	printf("队尾元素:%s %d\n",pBack->name,pBack->age);

	while(Size_LinkQueue(queue) > 0)
	{
		//获得队头元素
		struct Person *person = (struct Person *)Front_LinkQueue(queue);
		//打印队头元素
		printf("Name:%s Age:%d\n", person->name,person->age);
		//弹出队头元素
		Pop_LinkQueue(queue);
	}


	//销毁队列
	Destroy_LinkQueue(queue);

}

int main(){

	test();

	system("pause");
	return EXIT_SUCCESS;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值