队列类型定义:
队列的操作与栈的操作类似,不同的是,删除是在队头进行。
队列分类:
** 顺序队列**:与栈相似(数组),无非就是多了一个指针。
简单的讲讲顺序队列,元素入队,队尾指针往后加一,元素出队,队头指针往后加一。
现在我们设想一下,前面有一个数组,我们先存放了一些数据入队,后面进行出队操作,之后再入队,那么此时,假设,一个数组a的大小为10,经过这些操作之后,队头元素在a[99],此时如果我们还要进行操作时,发现队列的长度不够了,但是实际上,a[99]前面仍然有一大片空间没有被利用,这种现象我们称之为"假溢出"。为了避免"假溢出"现象,此时我们使用循环队列。循环队列将在下一章详细介绍。
** 链式队列**:链式队列是指采用链表存储结构实现的队列。根据队列的性质,链表需要两个指针,队头,队尾各一个指针,队头进行出队操作,队尾进行入队操作。
链式队列示意图:
要注意的是有一个头结点不存放数据,这一点和链表相似。
基本操作:
- 初始化队列
- 判断队列是否为空
- 元素入队
- 遍历队列
- 取首元素
- 元素出队且撤销申请空间
代码:
下面是分块代码,后面有完整代码。
初始化队列
#pragma once
# include <stdio.h>
# include <stdlib.h>
typedef int ElemType;
typedef struct QNODE
{
int data; //存放数据
struct QNODE *next; //指针域
}QNODE,*PQNODE;
typedef struct
{
PQNODE front;
PQNODE rear;
}QUEUE;
**void InitQueue(QUEUE *L)
{
L->front = L->rear = (PQNODE)malloc(sizeof(QNODE));
L->front->next =L->rear->next= NULL;
}
判断队列是否为空
int EmptyQueue(QUEUE *L)
{
if (L->front->next == NULL)
{
printf("队列已空!\n");
return 1;
}
else
return 0;
}
元素入队
void PushQueue(QUEUE *L, ElemType e)
{
PQNODE s = (PQNODE)malloc(sizeof(QNODE));
s->next = NULL;
s->data = e;
L->rear->next = s;
L->rear = s;
}
遍历队列
void TraverseQueue(QUEUE *L)
{
PQNODE t = (PQNODE)malloc(sizeof(QNODE));
t = L->front;
t = t->next;
while (t != NULL)
{
printf("%3d->", t->data);
t = t->next;
}
}
取首元素
void GetQueueFirstItem(QUEUE *L, ElemType *e)
{
PQNODE t = (PQNODE)malloc(sizeof(QNODE));
t = L->front;
t = t->next; //指向有效节点
*e = t->data;
}
元素出队且撤销申请空间****
void OutQueue(QUEUE *L)
{
PQNODE t = (PQNODE)malloc(sizeof(QNODE));
t = L->front;
while (L->front->next != NULL)
{
L->front = L->front->next;
printf("%5d->", t->next->data);
free(t);
t = L->front;
}
}
头文件代码:
#pragma once
# include <stdio.h>
# include <stdlib.h>
typedef int ElemType;
typedef struct QNODE
{
int data; //存放数据
struct QNODE *next; //指针域
}QNODE,*PQNODE;
typedef struct
{
PQNODE front; //队头(指针)进行删除
PQNODE rear; //队尾(指针)压入数据
}QUEUE;
//队列初始化
void InitQueue(QUEUE *L)
{
L->front = L->rear = (PQNODE)malloc(sizeof(QNODE));
L->front->next =L->rear->next= NULL; //是使队头,队尾的指针域指向空,而不是让队头队尾为空
}
int EmptyQueue(QUEUE *L)
{
if (L->front->next == NULL) //队头的指针域为空,即后面即没有元素连接
{
printf("队列已空!\n");
return 1;
}
else
return 0;
}
//压入元素
void PushQueue(QUEUE *L, ElemType e)
{
PQNODE s = (PQNODE)malloc(sizeof(QNODE));
s->next = NULL;
s->data = e;
//尾插法
L->rear->next = s;
L->rear = s;
}
void DeleteQueue(QUEUE *L, ElemType*e)
{
if (EmptyQueue(L))
{
printf("队列已空,无法出队!\n");
return;
}
else
{
//队列有一个头结点,所以需要指针往后移一个单元,指向有效数据
PQNODE m = (PQNODE)malloc(sizeof(QNODE));
m = L->front;
m = m->next; //指向有效数据
*e = m->data;
PQNODE t = (PQNODE)malloc(sizeof(QNODE));
t = L->front;
L->front = L->front->next; //头结点往后移
free(t); //释放头结点
}
}
//取队头元素
void GetQueueFirstItem(QUEUE *L, ElemType *e)
{
//用一个临时结点来指向队头,因为队列的操作一般不会直接用头结点进行操作,否则很容易使后面的操作混乱
PQNODE t = (PQNODE)malloc(sizeof(QNODE));
t = L->front;
t = t->next; //指向有效节点
*e = t->data;
}
void TraverseQueue(QUEUE *L)
{
PQNODE t = (PQNODE)malloc(sizeof(QNODE));
t = L->front;
t = t->next;
while (t != NULL)
{
printf("%3d->", t->data);
t = t->next;
}
}
//元素全部出队,并撤销空间
void OutQueue(QUEUE *L)
{
//这时可以直接对队头进行操作
PQNODE t = (PQNODE)malloc(sizeof(QNODE));
t = L->front;
while (L->front->next != NULL)
{
L->front = L->front->next;
printf("%5d->", t->next->data);
free(t);
t = L->front;
}
}
源文件代码:
# include <stdio.h>
# include <stdlib.h>
# include "Queue.h"
int main()
{
QUEUE L;
InitQueue(&L);
int a[10];
printf("请输入数据!\n");
for (int i = 0; i < 10; i++)
{
scanf("%d", &a[i]);
PushQueue(&L, a[i]);
}
printf("抛出队头元素!\n");
int e;
GetQueueFirstItem(&L, &e);
printf("队头元素为:%d", e);
printf("\n");
printf("遍历队列!\n");
TraverseQueue(&L);
printf("删除元素(队头)!\n");
DeleteQueue(&L, &e);
printf("删除的元素为:%d\n",e);
printf("删除所有元素,并且撤销所有空间!\n");
OutQueue(&L);
system("pause");
return 0;
}
代码运行截图: