数据结构笔记 九:队列

说明:本笔记依照《王道论坛-数据结构》视频内容整理。

队列是只允许一端进行插入,在另一端删除线性表
在这里插入图片描述

一、操作

InitQueue(&Q):初始化队列。构造一个空队列 Q。

DestroyQueue(&Q):销毁队列。销毁并释放队列 Q 所占用的内存空间。

EnQueue(&Q,x):入队。若队列 Q 未满,将 x 加入,使之成为新的对尾。

DeQueue(&Q,&x):出队。若队列 Q 非空,删除对头元素,并用 x 返回。

GetHead(Q,&x):队头元素。若队列 Q 非空,则将对头元素赋值给 x。

二、队列的顺序存储实现

1、队列

#define MAXSIZE 10                      // 定义最大长度
typedef int ElemType;                   // 根据实际情况定义

typedef struct{
    ElemType data[MAXSIZE];             // 用数组存放数据元素(ElemType - 实际数据类型)
    int fornt,rear;                     // fornt - 对头指针,rear - 队尾指针
}QueueT;                                // Stack(列表)T(数据类型)Q(指针类型)

2、内存布局

在这里插入图片描述

3、空队列判断

空队列判断条件:rear == front

4、操作

1、InitQueue(&Q)

/****************************************
* 初始化队列
* q - 要操作的队列首地址
****************************************/
void initQueue(QueueT *q)
{
    q->rear = q->front = 0;
}

在这里插入图片描述

2、DestroyQueue(&Q)

使用静态分配方式实现队列,定义变量时,自动分配空间,变量回收时,销毁空间。

3、EnQueue(&Q,x)

/****************************************
* 入队
* q - 要操作的队列首地址
* x - 入队元素
****************************************/
int enQueue(QueueT *q,ElemType x)
{
    if(q->rear==MAXSIZE) return 1;             // 队列满
    q->data[q->rear] = x;                   // 将 x 插入队尾
    q->rear = q->rear + 1;                  // 队尾指针后移
    return 0;
}

在这里插入图片描述

4、DeQueue(&Q,&x)

/****************************************
* 出队
* q - 要操作的队列首地址
* x - 出队元素
****************************************/
int DeQueue(QueueT *q,ElemType *x)
{
    if(q->rear == q->front) return 0;       // 队列为空
    *x = q->data[q->front];                 // 提取对头元素
    q->front = q->front+1;                  // 队头后移
    // 移动数据
    for(int i=0;i<q->rear-q->front;i++){
        q->data[i] = q->data[q->front+i];
    }
    q->rear = q->rear-q->front;
    q->front = 0;
    // 以上两句不能颠倒

    return 0;
}

在这里插入图片描述

5、GetHead(&Q,&x)

/****************************************
* 打印队列
* q - 要操作的队列首地址
****************************************/
int GetHead(QueueT *q,ElemType *x)
{
    if(q->rear == q->front) return 0;       // 队列为空
    *x = q->data[q->front];                 // 提取对头元素

    return 0;
}

6、printfQueue(&Q)

/****************************************
* 打印队列
* q - 要操作的队列首地址
****************************************/
int printfQueue(QueueT *q)
{
    int i = 0;
    while(q->rear != q->front+i){
        printf("q->data[q->fornt+i] = %d\n",q->data[q->front+i]);
        i++;
    }

    return 0;
}

7、QueueEmpty(&Q)

/****************************************
* 判断队列是否为空
* q - 要操作的队列首地址
****************************************/
int queueEmpty(QueueT *q)
{
    if(q->rear == q->front) return 0;       // 队列为空
    else return 1;                          // 队列不为空
}

5、总结

问题:以上队列在执行出队操作后需要移动数据。

三、循环队列

核心:通过取模运算完成循环。
在这里插入图片描述
取模运算线状存储空间在逻辑上编程“环状”。

队列空条件:q->rear == q->front

队列已满条件:队尾指针的再下一个位置时队头,即(q->rear+1)%MAXSIZE == q->front

队列元素个数计算:(rear+MAXSIZE-front)%MAXSIZE

四、队列的链式存储实现

在这里插入图片描述

1、队列

typedef int ElemType;		    // 根据实际情况定义

typedef struct lNode{           // 定义链式队列结点类型
    ElemType data;              // 每个结点存放一个数据元素
    struct lNode *next;         // 指针指向下一个元素
}lNode;                         // lNode 强调是一个结点

typedef struct{                 // 链式队列
    lNode *front, *rear;        // 队列的队头和队尾
}LinkQueueT;

2、操作

1、InitQueue(&Q)

/****************************************
* 初始化队列
* q - 要操作的队列首地址
****************************************/
void initQueue(LinkQueueT *q)
{
    q->front = q->rear = (lNode*)malloc(sizeof(lNode));     // 创建头结点,并初始化队头和队尾指针
    q->front->next = NULL;                                  // 初始化头结点中 next 指针
}

在这里插入图片描述

2、isEmpty(Q)

/****************************************
* 判断队列是否为空
* q - 要操作的队列
****************************************/
int isEmpty(LinkQueueT q)
{
    if(q.front==q.rear) return 0;           // 队列为空
    else return 1;                          // 队列不为空
}

3、enQueue(&Q,x)

/****************************************
* 入队
* q - 要操作的队列首地址
* x - 要插入元素
****************************************/
void enQueue(LinkQueueT *q,ElemType x)
{
    lNode *s = (lNode*)malloc(sizeof(lNode));
    s->data = x;
    s->next = NULL;
    q->rear->next = s;
    q->rear = s;
}

在这里插入图片描述

4、deQueue(&Q,&x)

/****************************************
* 出队
* q - 要操作的队列首地址
* x - 要插入元素
****************************************/
int deQueue(LinkQueueT *q,ElemType *x)
{
    if(q->front==q->rear)   return 1;       // 空队列
    lNode *p = q->front->next;
    *x = p->data;                           // 用变量 x 返回头元素
    q->front->next = p->next;               // 修改头结点 next 指针
    if(q->rear==p) q->rear=q->front;        // 对最后一个结点进行处理,修改 rear 指针
    free(p);                                // 释放结点

    return 0;
}

在这里插入图片描述

五、总结

顺序存储:预分配的空间耗尽时队满。

链式存储:一般不会队满,除非内存不足。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值