1.链队列
链式队列----用链表实现,链式队列就是一个操作受限的单向链表
之前单链表结构体设计的时候,当时发现头节点所需要的成员变量(next域),有效节点里都有,所以我们当时单链表头节点直接借用别人有效数据节点的结构体设计
所以我们之前常说头节点的数据域不使用,浪费掉。
现在设计链式队列,就会发现头节点需要两个指针域(front和rear)
这时再让头节点借用有效数据节点的结构体设计就不合适
所以我们需要将链式队列的头节点重新设计
这时有一个问题:重新设计的头节点需不需要数据域?
2.链式队列的头文件与函数声明
#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(struct LQueue* lq);
//入队
bool Push(struct LQueue* lq, ELEM_TYPE val);
//出队(还需要一个输出参数rtval,将出的值带出来)
bool Pop(PLQueue lq, ELEM_TYPE* rtval);
//获取队头元素值(还需要一个输出参数rtval,将出的值带出来)
bool Top(PLQueue lq, ELEM_TYPE* rtval);
//判空
bool IsEmpty(PLQueue lq);
//判满
bool IsFull(PLQueue lq);
//查找
struct Node* Search(PLQueue lq, ELEM_TYPE val);
//获取有效元素个数
int Get_length(PLQueue lq);
//清空
void Clear(PLQueue lq);
//销毁
void Destroy(PLQueue lq);
//打印
void Show(PLQueue lq);
3.函数
3.1初始化
将头节点两个指针置空
//初始化
void Init_LQueue(struct LQueue* lq)
{
//assert
lq->front = NULL;
lq->rear = NULL;
}
3.2入队
入队,相当于单链表尾插,但是有队尾指针,方便操作
有一种特殊情况:插入之前是空的队列
//入队
bool Push(struct LQueue* lq, ELEM_TYPE val)
{
//assert
//链式结构 入队 不需要判满
//1.购买新节点
struct Node * pnewnode = (struct Node *)malloc(1 * sizeof(struct Node));
assert(pnewnode != NULL);
pnewnode->data = val;
//2.找到合适插入位置(队尾插入)
//3.插入
//特殊情况:如果入队之前,是一个空的队列
if(IsEmpty(lq))
{
lq->front = lq->rear = pnewnode;
pnewnode->next = NULL;
}
else
{
pnewnode->next = lq->rear->next;
lq->rear->next = pnewnode;
lq->rear = pnewnode;//插入之后,将队尾指针更新一下
}
return true;
}
3.3出队
单链表头删,但是要注意头指针的值
只要队列不空,则先让rtval 将值带出来
特殊情况: 要判断一下 出的那个节点是否是仅剩下的唯一一个节点
//出队(还需要一个输出参数rtval,将出的值带出来)
bool Pop(PLQueue lq, ELEM_TYPE* rtval)
{
//assert
if(IsEmpty(lq))
{
return false;
}
//只要队列不空,则先让rtval 将值带出来
*rtval = lq->front->data; //这一步 不要忘
//特殊情况: 要判断一下 出的那个节点是否是仅剩下的唯一一个节点
if(lq->front->next == NULL)//仅有一个有效节点
{
struct Node *p = lq->front;//p == lq->rear; ok
free(p);
lq->front = lq->rear = NULL;
}
else
{
struct Node *p = lq->front;
lq->front = p->next;
free(p);
}
return true;
}
3.4获取队头元素值
//获取队头元素值(还需要一个输出参数rtval,将出的值带出来)
bool Top(PLQueue lq, ELEM_TYPE* rtval)
{
//assert
if(IsEmpty(lq))
{
return false;
}
//只要队列不空,则先让rtval 将值带出来
*rtval = lq->front->data; //这一步 不要忘
return true;
}
3.5判空
bool IsEmpty(PLQueue lq)
{
//assert
return lq->front == NULL;
}
3.6查找
//查找
struct Node* Search(PLQueue lq, ELEM_TYPE val)
{
//assert
if(IsEmpty(lq))
{
return false;
}
//不需要前驱的那个for 去遍历
for(struct Node*p = lq->front; p!=NULL; p=p->next)
{
if(p->data == val)
{
return p;
}
}
return NULL;
}
3.7获取有效元素个数
//获取有效元素个数
int Get_length(PLQueue lq)
{
int count = 0;
for(struct Node*p = lq->front; p!=NULL; p=p->next)
{
count++;
}
return count;
}
3.8销毁
//销毁
void Destroy(PLQueue lq)
{
struct Node* p = lq->front;
struct Node* q = NULL;
while(p != NULL)
{
q = p->next;
free(p);
p = q;
}
lq->front = lq->rear = NULL;
}
4.链队列的源文件与函数实现
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include "list_queue.h"
//初始化
void Init_LQueue(struct LQueue* lq)
{
//assert
lq->front = NULL;
lq->rear = NULL;
}
//入队
bool Push(struct LQueue* lq, ELEM_TYPE val)
{
//assert
//链式结构 入队 不需要判满
//1.购买新节点
struct Node * pnewnode = (struct Node *)malloc(1 * sizeof(struct Node));
assert(pnewnode != NULL);
pnewnode->data = val;
//2.找到合适插入位置(队尾插入)
//3.插入
//特殊情况:如果入队之前,是一个空的队列
if(IsEmpty(lq))
{
lq->front = lq->rear = pnewnode;
pnewnode->next = NULL;
}
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 将值带出来
*rtval = lq->front->data; //这一步 不要忘
//特殊情况: 要判断一下 出的那个节点是否是仅剩下的唯一一个节点
if(lq->front->next == NULL)//仅有一个有效节点
{
struct Node *p = lq->front;//p == lq->rear; ok
free(p);
lq->front = 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 将值带出来
*rtval = lq->front->data; //这一步 不要忘
return true;
}
//判空
bool IsEmpty(PLQueue lq)
{
//assert
return lq->front == NULL;
}
//判满 //链式结构不需要判满
//查找
struct Node* Search(PLQueue lq, ELEM_TYPE val)
{
//assert
if(IsEmpty(lq))
{
return false;
}
//不需要前驱的那个for 去遍历
for(struct Node*p = lq->front; p!=NULL; p=p->next)
{
if(p->data == val)
{
return p;
}
}
return NULL;
}
//获取有效元素个数
int Get_length(PLQueue lq)
{
int count = 0;
for(struct Node*p = lq->front; 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 = NULL;
while(p != NULL)
{
q = p->next;
free(p);
p = q;
}
lq->front = lq->rear = NULL;
}
//打印
void Show(PLQueue lq)
{
for(struct Node*p = lq->front; p!=NULL; p=p->next)
{
printf("%d ", p->data);
}
printf("\n");
}