链式队列

链式队列

链式队列主要应用的是单链表,先设计一个单链表:

typedef struct Node
{
	int data;//数据域,没存放节点的值
	struct Node* next;//指针域,存放下一个节点的地址
}Node,*PNode;

单链表的特点

优点: 插入和删除不用移动元素,头删的时间复杂度O(1) 尾删的时间复杂度O(n)

为什么头删的时间复杂度O(1) 尾删的时间复杂度O(n)呢

第一个节点和最后一个节点最直接差别在于: 第一个节点的地址我们一直用头结点来保存着,而最后一个节点我们得依次遍历过去。

  • 我们可以改造一下,让头部操作和尾部操作时间复杂度都为O(1):
    我们可以把头结点单独设计一下,不改动数据节点的结构:
//重新设计的头结点
typedef struct LQueue
{
	struct Node* prior;
	struct Node* tail;
}Lqueue,*PLQueue;

链式队列所需的操作

//增删改查
//初始化
void InitLQueue(PLQueue plq);

//入队
bool Push(PLQueue plq,int val);

//获取第一个节点的值,但不删除
bool Get_Top(PLQueue plq, int* rtval);

//出队,获取第一个节点的值,并且删除掉
bool Pop(PLQueue plq, int* rtval);

//判空
bool IsEmpty(PLQueue plq);

//链式队列不需要判满
//bool IsFull(PLQueue plq);

//获取元素有效个数
int Get_length(PLQueue plq);

//清空
bool Clear(PLQueue plq);

//销毁
void Destroy(PLQueue plq);

链式队列具体代码实现

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include"lqueue.h"

//增删改查
//初始化
void InitLQueue(PLQueue plq)
{
	assert(plq != NULL);
	if (plq == NULL)
		return;

	plq->prior = NULL;//初始化对头和对尾
	plq->tail = NULL;
}

//入队
bool Push(PLQueue plq, int val)
{
	assert(plq != NULL);
	if (plq == NULL)
		return false;

	Node* pnewnode = (Node*)malloc(sizeof(Node));//给插入的节点申请一个空间
	assert(pnewnode != nullptr);//判断其不为空

	pnewnode->data = val;  //把要插入的值给申请的新节点
	pnewnode->next = NULL;//当没有一个元素时,这一步不能少

	if (plq->prior == NULL)//判断当链式队列中没有一个元素,需要改变两个指针域
	{
		plq->prior = pnewnode;//插入的新节点可以是队列的头,也可以是队列的尾
		plq->tail = pnewnode;
	}
	else
	{
		pnewnode->next = plq->tail->next;//队尾的next域存放新节点

		plq->tail->next = pnewnode;//将新节点的值赋给队尾的next域
		plq->tail = pnewnode;//之后队尾的新节点成为新队列的队尾
	}
	return true;
}

//获取第一个节点的值,但不删除
bool Get_Top(PLQueue plq, int* rtval)//rtval是一个指针,指向第一个节点
{
	assert(plq != NULL && rtval != NULL);//断言
	if (plq == NULL || rtval == NULL)
		return false;

	//判空
	if (IsEmpty(plq))  //保证最起码有一个节点
		return false;

	//先通过输入参数获取值
	Node* p = plq->prior;       //将队头赋给Node *类型的指针p
	*rtval = p->data;           //将指针p获取的值赋给指针rtval

	return true;
}

//出队,获取第一个节点的值,并且删除掉
bool Pop(PLQueue plq, int *rtval)
{
	assert(plq != NULL && rtval != NULL);//断言
	if (plq == NULL||rtval==NULL)
		return false;

	//判空
	if (IsEmpty(plq))  //保证最起码有一个节点
		return false;

	//先通过输入参数获取值
	Node* p = plq->prior;
	*rtval = p->data;
	
	//出队的是否是唯一的一个节点
	if (p->next == NULL)
	{
		plq->prior = plq->tail = NULL;	//如果队列的next域为空,出队唯一一个节点,则队头和队尾都为空(也就是队头和队尾都指向next域)
   	}
	else
	{
		plq->prior = p->next;//如果队列不是只有一个节点,则队头变成队头指向的next域
	}
	//释放掉出队的元素
	free(p);
	p = NULL;
	return true;
}

//判空
bool IsEmpty(PLQueue plq)
{
	assert(plq != NULL);
	if (plq == NULL)
		return false;

	return plq->prior == NULL;//队头为空则整个队列为空
}

//获取元素有效个数
int Get_length(PLQueue plq)
{
	assert(plq != NULL);  //断言
	if (plq == NULL)
		return -1;

	int count = 0;//count为一个计数器,用来计算队列的长度
	for (Node* p = plq->prior; p != NULL; p = p->next)
	{
		count++;
	}
	return count;
}
//清空
bool Clear(PLQueue plq)
{
	Destroy(plq);
	return true;
}

//销毁
void Destroy(PLQueue plq)
{
	assert(plq != NULL);
	if (plq == NULL)
		return ;

	Node* p = NULL;//申请一个临时指针,接下来需要一直指向第一个节点

	while (IsEmpty(plq))//只要队列不空,就一直删除第一个节点
	{
		p = plq->prior;//p指向第一个节点
		plq->prior = p->next;//头结点的指针域指向第二个节点
		free(p);//释放指针p
		p = NULL;
	}
	plq->prior = plq->tail = NULL;//当队头和队尾都为空时,销毁结束
	return;
}

测试代码:

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include"lqueue.h"

int main()
{
	LQueue lq;
	InitLQueue(&lq);

	for (int i = 0; i < 20; i++)
	{
		Push(&lq, i);
	}
	printf("count = %-5d", Get_length(&lq));
	printf("\n");
	int val;
	while (!IsEmpty(&lq))
	{
		Pop(&lq, &val);
		printf("%-5d", val);
	}
	printf("\n");
	printf("count = %-5d", Get_length(&lq));
	return 0;
}

测试结果

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值