基本知识
队列ADT:
像栈一样,队列(queue)也是表。然而,使用队列时插入在一段进行,而删除在另一端进行。
队列模型:
对列的基本操作是
Enqueue(入队)--------他是在表的末端(叫做队尾(rear))插入一个元素。
Dequeue(出队)-------他是删除(或者返回)表的开头(叫做队头(front)的元素。
像栈一样:链表的实现和数组实现都给出快速的O(1)运行时间。
链队列:
前面提过当用户无法预估所用队列的最大长度,应采用链队列。
链队列是采用链式存储结构实现的队列。链队列通常采用单链表来表示。
既然这样,就必须要有两个指针———一个指向队头元素,一个指向队尾元素。
这样才能唯一确定。同样为了操作方便起见,给链队列添加一个头节点。
初始化时将头指针和尾指针指向该头节点,并将头指针始终指向头节点。
链队列的存储结构:
既然是链队列就必须要有节点,节点包含数据域和指向下一个节点的指针*next
而另外两个指针:头指针,尾指针来操作节点的插入,删除等操作。
我们知道指针只能指向它类型相同的数据域。
所以在声明时,头指针和尾指针应当是队列的节点的类型。
算法描述:
typedef struct QNode {
struct QNode* Next;
QElemtype date;
}QNode, * QueuePtr; //节点typedef struct {
QueuePtr front;
QueuePtr rear;
}LinkQueue; //头指针和尾指针
初始化:
和链表的初始化相同,队列的初始化就是构造一个只有一个头节点的空队。
int InitQueue(LinkQueue* Q)
{
Q->front = (QueuePtr)malloc(sizeof(QNode));//生成新的节点
Q->rear = Q->front;
if (!Q->front)
exit(-1);
Q->front->Next = NULL;//头节点的指针域置空
return 0;
}
入队:
入队时每次动态分配一个存储空间(节点)将元素放入该节点的数据域。指针域置空(为了让下一个元素插入)
1先让原本的队尾节点指向该节点. 2再让尾指针指向该节点(此时该节点就是尾节点)。
算法描述:
int EnQueue(LinkQueue* Q, QElemtype e)
{
QueuePtr P = (QueuePtr)malloc(sizeof(QNode));
if (!P)
exit(-1);
P->date = e;
P->Next = NULL;
Q->rear->Next = P;
Q->rear = P;
return 0;
}
出队:
特点:头节点出,先要判断是否为空队列,其次释放节点的空间。
算法步骤:
1判断队列是否为空。
2临时保存队头元素的值,以便释放节点的空间。
3修改头节点的指针域,指向下一个节点。(所谓的出队)。
4判断出队元素是否为最后一个元素,若是,则将队尾指针重新赋值,指向头节点。
5释放节点空间(2步骤保存了该节点数据域的值,可以在子函数中打印出来)
(4步骤,当删除的是队列的最后一个节点时,尾指针就没有指向的地方所以将尾指针指向头节点)
算法描述;
int DeQueue(LinkQueue* Q)
{
if (Q->rear == Q->front)
return -1;
QueuePtr P;
P = (QueuePtr)malloc(sizeof(QNode));
P = Q->front->Next; //将P指向头节点
int e = P->date; //保存p节点的数据域
Q->front->Next = P->Next; //修改头节点的指针域
if (Q->rear == P)
Q->rear = Q->front;
free(P);
return 0;
}
判断队空:
当头指针和尾指针同时指向一个节点时队列就为空。
算法描述:
int JustQueue(LinkQueue* Q)
{
if (Q->rear == Q->front)
printf("队列为空");
else
printf("队列不为空");
return 0;
}
(注意这里的参数也可以为(LinkQueue Q)当为这种形式时,调用传递的实参就为(Q)
函数内部就不能用指针类型的箭头"->"而要用点运算符)(因为不改变该队列)只是判断。
清空队列:
算法步骤:
1将尾指针指向头节点的下一个节点。
2.释放头指针指向的节点
3.将头指针指向(1步骤后)尾指针指向的节点
4.利用while将123步骤循环知道头节点指向的空间为NULL为止。
int DestoryQueue(LinkQueue* Q)
{
while (Q->front)
{
Q->rear = Q->front->Next;//将尾指针指向头节点的下一个节点
free(Q->front);
Q->front = Q->rear;
}
return 0;
}
打印队列:
将头指针指向的头节点的下一个节点的数据域打印,下一步将头指针往后移一位直至头指针和尾指针指向同一个节点为止,利用循环打印。
int PrintfQueue(LinkQueue Q)
{
QElemtype e;
if (Q.rear == Q.front)
{
printf("队列为空");
return 0;
}
else
{
while (Q.front->Next != NULL)
{
e = Q.front ->Next->date;
printf("%d",e);
Q.front = Q.front->Next;
}}
}
总代码为:
#define _CRT_SECURE_NO_WARNINGS 1
typedef int QElemtype;
#include <stdlib.h>
#include <stdio.h>
typedef struct QNode {
struct QNode* Next;
QElemtype date;
}QNode, * QueuePtr;
typedef struct {
QueuePtr front;
QueuePtr rear;
}LinkQueue;
LinkQueue Q;
//初始化链式队列
int InitQueue(LinkQueue* Q)
{
Q->front = (QueuePtr)malloc(sizeof(QNode));//分配Qnode类型的空间
Q->rear = Q->front;
if (!Q->front)
exit(-1);
Q->front->Next = NULL;//头节点的指针域置空
return 0;
}
//入队
int EnQueue(LinkQueue* Q, QElemtype e)
{
QueuePtr P = (QueuePtr)malloc(sizeof(QNode));
if (!P)
exit(-1);
P->date = e;
P->Next = NULL;
Q->rear->Next = P;
Q->rear = P;
return 0;
}
//出队
int DeQueue(LinkQueue* Q)
{
if (Q->rear == Q->front)
return -1;
QueuePtr P;
P = (QueuePtr)malloc(sizeof(QNode));
P = Q->front->Next; //将P指向头节点
int e = P->date; //去除头节点的数据域
Q->front->Next = P->Next; //将P设置为新的头节点
if (Q->rear == P)
Q->rear = Q->front; //如果队头同时为队尾则修改队尾指针
free(P);
return 0;
}
//判断队空
int JustQueue(LinkQueue* Q)
{
if (Q->rear == Q->front)
printf("队列为空");
else
printf("队列不为空");
return 0;
}
//清空队列
int DestoryQueue(LinkQueue* Q)
{
while (Q->front)
{
Q->rear = Q->front->Next;//将尾指针指向头节点的下一个节点
free(Q->front);
Q->front = Q->rear;
}
return 0;
}
//打印队列
int PrintfQueue(LinkQueue Q)
{
QElemtype e;
if (Q.rear == Q.front)
{
printf("队列为空");
return 0;
}
else
{
while (Q.front->Next != NULL)
{
e = Q.front ->Next->date;
printf("%d",e);
Q.front = Q.front->Next;
}
}
}
void menue9()
{
int i = 0;
printf("-----------主菜单---------------\n");
printf("1-------------入队\n");
printf("2-------------出队\n");
printf("3-------------判断队空\n");
printf("4-------------清空队列\n");
printf("5-------------打印队列\n");
printf("0------退出\n");
do {
printf("请选择:\n");
scanf("%d", &i);
switch (i) {
case 1:
{
int e;
printf("请输入入队元素");
scanf("%d", &e);
EnQueue(&Q, e);
break;
}
case 2:
{
DeQueue(&Q);
break;
}
case 3:
{
JustQueue(&Q);
break;
}
case 4:
{
DestoryQueue(&Q);
break;
}
case 5:
{
PrintfQueue(Q);
break;
}
case 0:
printf("正常退出");
return 0;
default:
printf("输入错误");
}
} while (1);
}
int main()
{
InitQueue(&Q);
menue9();
return 0;
}
以上就是队列链式存储的内容,如有错误,希望可以指出。