0
点赞
收藏
分享

微信扫一扫

2022.4.13 链式队列

霸姨 2022-04-14 阅读 54

1. 栈和循环队列

:不管用什么方式去实现,都可以保证入栈和出栈的时间复杂度为O(1)
循环队列:顺序表实现的队列,入队时间复杂度为O(1),出队时间复杂度为O(n)
队列中的三个难点以及解决方案:
① 如何保证顺序表实现的队列的入队和出队时间复杂度为O(1)
答:出队的时候,不再挪动数据向前覆盖,而是数据不动,队头指针向后移动(臆想成一个环)
② 臆想成环之后,判空和判满条件冲突了?
答:1)设计成一个计数器;
2)队尾浪费一个空间,不再存储数据,而是作为一个标记
③ 循环队列的求长度公式:length = (rear - front + MAX_SIZE) %MAX_SIZE

2. 链式队列

链式队列的需求:第一时间可以找到头(首元素);第一时间可以找到尾(尾元素);得有一个链表去存储数据;
解决方法:给头节点加一个尾指针,就可以满足其需求;因此,头结点结构体里成员比有效数据结构体成员多,不在让头结点借助有效数据节点的结构体设计,而是让头结点重新设计自身的结构体设计
如下图:
在这里插入图片描述
*入队:在队尾入,相当于尾插;出队:在队头出,头删

3.链式队列的结构体设计

(1) 头结点既然重新设计,完全可以将之前的数据域扔掉,因为链队列的头结点只需要两个指针域即可(队头指针和队尾指针)

typedef int ELEM_TYPE;
//有效数据节点的结构体设计----指针域和数据域
typedef struct Node
{
	ELEM_TYPE data;//数据域
	struct Node* next;//指针域
}Node,*PNode;

//头节点的结构体设计----两个指针域
typedef struct LQueue
{
	struct Node* front;//保存有效数据节点的地址
	struct Node* rear;
}LQueue, *PLQueue;

4 可执行函数

注意的两个函数:
① 出队:在队头出,相当于头删,有两种情况
正常情况下出队,收到影响的只有一个指针域——front ;特殊情况下出队,受到影响的指针域有两个——front 和 rear,如图:
在这里插入图片描述
在这里插入图片描述
② 入队:在队尾入,相当于尾插,有两种情况
正常特殊情况下,里面已经有元素了(不是一个空队列);特殊情况下,这个队列是一个空队列,如果是一个空队列,入队的元素既是队头也是队尾。
5. 代码实现
ist_queue.h文件

#pragma once

//链式队列的结构体设计
typedef int ELEM_TYPE;
//有效数据节点的结构体设计----指针域和数据域
typedef struct Node
{
	ELEM_TYPE data;//数据域
	struct Node* next;//指针域
}Node,*PNode;

//头节点的结构体设计----两个指针域
typedef struct LQueue
{
	struct Node* front;//保存有效数据节点的地址
	struct Node* rear;
}LQueue, *PLQueue;
//链式队列可执行函数---增删改查
//初始化
void Init_LQueue(PLQueue lq);

//入队
bool Push(PLQueue lq, ELEM_TYPE val);

//出队(这里需要知道出队的值,通过输出参数rtval带出来)
bool Pop(PLQueue lq, ELEM_TYPE * rtval);//系统提供的是小写

//获取头元素值(这里需要知队头的值,通过输出参数rtval带出来)
bool Top(PLQueue lq, ELEM_TYPE* rtval);

//搜索
struct Node* Search(PLQueue lq, ELEM_TYPE val);

//判空
bool IsEmpty(PLQueue lq);

//判满---链式结构不需要判满
//bool IsFull(PLQueue lq);

//获取有效长度
int Get_length(PLQueue lq);

//清空
void Clear(PLQueue lq);

//销毁
void Destroy(PLQueue lq);

//打印
void Show(PLQueue lq);

ist_queue.cpp文件

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


//初始化
void Init_LQueue(PLQueue lq)//PLQueue头结点
{
	assert(lq != NULL);
	if (lq == NULL)
	{
		return;
	}
	lq->front = NULL;
	lq->rear = NULL;
}


//入队
bool Push(PLQueue lq, ELEM_TYPE val)
{
	//assert;
	//不需要判满
	struct Node* pnewnode = (struct Node*)malloc(1 * sizeof(struct Node));
	assert(pnewnode != NULL);//申请成功
	pnewnode->data = val;

	if (IsEmpty(lq))//特殊情况下:空队列
	{
		pnewnode->next = lq->front;
		lq->front = lq->rear = pnewnode;//如果是一个空队列,入队的元素既是队头也是队尾
	}
	else//正常情况下
	{
		pnewnode->next = lq->rear->next;
		lq->rear->next = pnewnode;
		//更新一下队尾指针,重新让它指向新插入的尾结点
		lq->rear = pnewnode;
	}

	return true;
}

//出队(这里需要知道出队的值,通过输出参数rtval带出来)
bool Pop(PLQueue lq, ELEM_TYPE* rtval)
{
	//assert;
	if (IsEmpty(lq))
	{
		return false;
	}//至少存在一个节点
	*rtval = lq->front->data;//第一个元素的数据域带出来

	//if (lq->front->next == NULL)//判断剩余元素是否仅剩一个
	if (Get_length(lq) == 1)
	{
		free(lq->front);
		lq->front = NULL;
		lq->rear = NULL;
	}
	else//正常情况下,剩余元素不止一个
	{
		struct Node* p = lq->front;
		lq->front = p->next;
		free(p);
	}

	return true;
}

//获取头元素值(这里需要知队头的值,通过输出参数rtval带出来)
bool Top(PLQueue lq, ELEM_TYPE* rtval)
{
	//assert
	if (IsEmpty(lq))
	{
		return false;
	}
	*rtval = lq->front->data;
	return true;
}


//搜索---队头到队尾遍历一遍,需要不需要前驱的for循环
struct Node* Search(PLQueue lq, ELEM_TYPE val)//队头到队尾遍历一遍
{
	struct Node* p = lq->front;
	for (p; p != NULL; p = p->next)
	{
		if (p->data == val)
		{
			return p;
		}
	}

	return NULL;

}

//判空
bool IsEmpty(PLQueue lq)
{
	return lq->front == NULL;
}

//判满---链式结构不需要判满
//bool IsFull(PLQueue lq);

//获取有效长度
int Get_length(PLQueue lq)
{
	int count = 0;
	struct Node* p = lq->front;
	for (p; p != NULL; p = p->next)
	{
		count++;
	}
	return count;
}

//清空
void Clear(PLQueue lq)
{
	Destroy(lq);//对于链式结构来说,清空就是销毁
}

//销毁
void Destroy(PLQueue lq)
{
	struct Node* p = lq->front;
	struct Node* q = lq->front;
	while (p != NULL)
	{
		q = p->next;
		free(p);
		p = q;
	}
	lq->front = lq->rear = NULL;
}

//打印
void Show(PLQueue lq)
{
	struct Node* p = lq->front;
	for (p; p != NULL; p = p->next)
	{
		printf("%d ", p->data);
	}
	printf("\n");
}

list_queue.cpp主函数

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include"list_queue.h"
//链式队列
int main()
{
	struct LQueue head;
	Init_LQueue(&head);
	for (int i = 0; i < 20; i++)
	{
		Push(&head, i + 1);
	}
	Show(&head);
	printf("length=%d\n", Get_length(&head));

	ELEM_TYPE tmp;
	bool tag = Pop(&head, &tmp);//队列,先进先出,这块出1
	if (tag)
	{
		printf("pop = %d\n", tmp);
	}
	Show(&head);
	printf("length=%d\n", Get_length(&head));

	ELEM_TYPE flag;
	bool tag2 = Top(&head, &flag);//队列,先进先出,这块出1
	if (tag2)
	{
		printf("top = %d\n", flag);
	}
	Show(&head);
	printf("length=%d\n", Get_length(&head));


	Destroy(&head);
	Show(&head);
	printf("length=%d\n", Get_length(&head));

	return 0;
}

运行结果:
在这里插入图片描述
注意:销毁之后打印出来是空行,图中空白地方

举报

相关推荐

0 条评论