DS-队列

前言


队列是一种先进先出线性表,队列是线性表的特化,也具有线性表的性质分为:顺序队列与链式队列,链式队列与线性表的单链表相似只不过链式队列只允许从头部进行删除、尾部进行插入。需要为链式队列创建一个头结点包括两个指针,指向队头的指针(front)与指向队尾的指针(rear)。当两个指针相等时队列为空。

文中结合一博客中链队列的程度,通过对于代码的内容进行注释,对链队列的基本内容进行总结方便以后的复习。

链队列


链队列的基本操作包括有:

  • 初始化队列
  • 创建队列
  • 进队操作
  • 出队操作
  • 获取队列长度
  • 打印队列元素
  • 清空队列
  • 销毁队列

链队列的基本操作程序

LinkQueue.h

#ifndef LINKQUEUE_H
#define LINKQUEUE_H
typedef int ElemType;  //队列的数据类型
typedef struct node{
    ElemType data; //队列的数据类型
    struct node *next; //指向下一个结点
}QueNode,*QuePtr;
typedef struct{
    QuePtr front; //指向队头的指针
    QuePtr rear; //指向队尾的指针
}LinkQueue;

void InitQueue(LinkQueue *q); //初始化队列

void CreateQueue(LinkQueue *q); //创建队列

void EnQueue(LinkQueue *q,ElemType e); //进队操作,将元素e压入队列中

void DeQueue(LinkQueue *q,ElemType *e); //出队操作,将出队的元素存入*e中

int GetQueueLength(LinkQueue *q); //获取队列的长度

void Print(LinkQueue *q); //打印队列的元素

void Clear(LinkQueue *q); //清空队列

void TopQueue(LinkQueue *q,ElemType *e); //返回队头的元素

#endif //LINKQUEUE_H

Queue.cpp

#include "LinkQueue.h"
#include <stdio.h>
#include <stdlib.h>
void InitQueue(LinkQueue *q) //初始化队列
{
    //构造一个有头结点的队列 
    q->front = q->rear = (QuePtr)malloc(sizeof(QueNode)); //初始化队头与队尾的指针指向头结点
    q->front->next = NULL;
}

void CreateQueue(LinkQueue *q) //创建队列
{
    InitQueue(q);
    printf("请输入要进队的元素以CTRL+Z结尾\n");
    int k;
    while((scanf("%d",&k)) != EOF)
        EnQueue(q,k);
}

void EnQueue(LinkQueue *q,ElemType e) //将元素e进队
{
    QuePtr temp = (QuePtr)malloc(sizeof(QueNode)); //创建新结点
    if(temp) //如果内存分配成功
    {
        temp->data = e; //初始化新结点的数据为e
        temp->next = NULL; //队列只能从队尾插入所以下一个结点初始化为NULL
        q->rear->next = temp; //将队尾结点的指针指向新结点,如果新结点为第一个结点则q->rear->next相当于q->front->next
        q->rear = temp; //将指向队尾的指针指向新结点
    }
}

void DeQueue(LinkQueue *q,ElemType *e) //队头的结点出队,将出队的结点的元素存入*e
{
    if(q->front == q->rear) //队列为空
        return;
    QuePtr temp = q->front->next; //初始化temp为要出队的结点的指针
    if(q->front->next == q->rear) //如果要出队的结点为最后一个结点,使q->rear指向头结点防止出现悬空的指针
        q->rear = q->front;
    *e = temp->data; //将出队的数据元素存入*e
    q->front->next = temp->next; //使下一个结点成为队头,如果没有下一个结点则为NULL
    free(temp); //删除要出队的结点
}

bool IsEmpty(LinkQueue *q) //判断队列是否为空
{
    if(q->front == q->rear)
        return true;
    return false;
}

int GetQueueLength(LinkQueue *q) //返回队列的长度
{
    QuePtr temp = q->front;
    int i = 0;
    while(temp != q->rear)
    {
        ++i;
        temp = temp->next;
    }
    return i;
}

void Clear(LinkQueue *q) //清空队列
{
    QuePtr temp = q->front->next;
    while(temp)
    {
        QuePtr tp = temp;
        temp = temp->next;
        free(tp);
    }
    temp = q->front;
    q->front = q->rear = NULL;
    free(temp);
}

void Destory(LinkQueue *q)//销毁队列
{
    while(q->front)
    {
     q->rear=q->front->next;
     free(q->front);
     q->front=q->rear;
    }
}

void Print(LinkQueue *q) //打印队列的元素
{
    if(q->front == q->rear){
        printf("队列内容为空!\n");
        return;
    } 

    QuePtr temp = q->front->next;
    while(temp != q->rear)
    {
        printf("%d ",temp->data);
        temp = temp->next;
    }
    printf("%d",temp->data);
    printf("\n");
}
void TopQueue(LinkQueue *q,ElemType *e) //返回队头的结点元素存入*e
{
    if(q->front == q->rear)
        return;
    *e = q->front->next->data;
}   
int main()
{
    LinkQueue q;
    //创建队列 
    CreateQueue(&q);
    //队列长度
    int len = GetQueueLength(&q);
    //判断队列长度是否为空
    if(IsEmpty(&q))
        printf("队列为空!\n");
    else
        printf("队列的长度为:%d\n",len);
    //打印队列元素 
    Print(&q);
    //获取队列头元素 
    int top;
    TopQueue(&q,&top);
    printf("队头的元素为:%d\n",top);
    //将队列中元素全部出队列   
    int k;
    printf("将队列中的所有元素出队:\n");
    for(int i = 0;i < len;++i)
    {
        DeQueue(&q,&k);
        printf("%d ",k);
    }
    printf("\n");
    //清空队列 
    Clear(&q);
    //打印队列元素 
    Print(&q);
    //销毁队列  
    Destory(&q);    
    return 0;
}

程序运行截图:

这里写图片描述

顺序队列(循环队列)


队列包括有顺序队列、链队列。上面的程序中便是链队列的基本操作,下面总结关于顺序队列的一些基本内容。
初始化空队列:令front=rear=0
元素入队列: ++rear
元素出队列: ++front
非空队列中, front指示队头元素;
非空队列中, rear指示队尾元素下一位置
空队列条件: front==rear
满队列条件: rear==MaxSize

设顺序队列的预定义长度为M,则:
当front=0,rear=M时,再有元素入队发生溢出
——真溢出
当front!=0,rear=M时,再有元素入队发生溢出
——假溢出

解决方案:

队首固定,每次出队剩余元素向下移动——浪费时间
循环队列:把队列设想成环形,让sq[0]接在sq[M-1]之后,若++rear==M,则令rear=0;

出现新问题:

新的问题便是当出现队空和对面的情况下,判断的条件均是:front == rear

如下图:

这里写图片描述

解决方案:

另外设一个标志以区别队空与队满条件
设记录实际队列元素个数的数据成员来区别
牺牲一个队列元素空间以区别队空与队满条件
队空:front==rear
队满:(rear+1)% M==front

总结


队列的应用的领域还比较广泛,最主要的是应用到图的遍历中,树的按层遍历输出,OS作业调度系统等。

线性表的基本内容主要包括以上的几个文章内容板块,还剩下有串的内容,有关串的内容主要涉及到是模式串的匹配,KMP算法,一个非常关键的串匹配算法。

猜你喜欢

转载自blog.csdn.net/gerald_jones/article/details/79179386
DS
今日推荐