数据结构 - 顺序队列的实行(C语言)

数据结构-顺序队列的实现

1 顺序队列的定义

线性表有顺序存储和链式存储,队列作为一种特殊的线性表,也同样存在这两种存储方式。我们先来看队列的顺序存储结构。

队列的顺序储存结构:用数组存储队列,为了避免当只有一个元素时,队头和队尾重合使得处理变得麻烦,所以引入两个指针:front指针指向队头元素,rear指针指向队尾元素的下一个位置,当front=rear时,为空队列,结构如下图所示。

假设是长度为5的数组,初始状态,空队列如下图左所示,front与 rear指针均指向下标为0的位置。然后入队a1、a2、a3、a4,front指针依然指向下标为0位置,而rear指针指向下标为4的位置,如下图右所示。

出队a1、a2,则front指针指向下标为2的位置,rear不变,如下图左所示,再入队a5,此时front指针不变,rear指针移动到数组之外。嗯?数组之外, 那将是哪里?如下图右所示。

问题还不止于此。假设这个队列的总个数不超过5个,但目前如果接着入队的话,因数组末尾元素已经占用,再向后加,就会产生数组越界的错误,可实际上,我们的队列在下标为0和1的地方还是空闲的。我们把这种现象叫做“假溢出"。

2 循环队列定义

所以解决"假溢出"的办法就是后面满了,就再从头开始,也就是头尾相接的循环。我们把队列的这种头尾相接的顺序存储结构称为循环队列。

刚才的例子继续,上图的rear可以改为指向下标为0的位置,这样就不会造成指针指向不明的问题了,如下图所示。

接着入队a6,将它放置于下标为0处,rear指针指向下标为1处,如下图左所示。若再入队a7,则rear指针就与front指针重合,同时指向下标为2的位置,如下图右所示。

  • 此时问题又出来了,我们刚才说,空队列时,front等于rear,现在当队列满
    时,也是front等于rear,那么如何判断此时的队列究竟是空还是满呢?
  • 办法一是设置一个标志变量flag, 当front == rear,且flag = 0时为队列空,
    当front== rear,且flag= 1 时为队列满。
  • 办法二是当队列空时,条件就是front = rear,当队列满时,我们修改其条件,保留一个元素空间。也就是说,队列满时,数组中还有一个空闲单元。
    例如下图所示,我们就认为此队列已经满了,也就是说,我们不允许上图右的情况出现。

我们重点来讨论第二种方法,由于rear可能比front大,也可能比front小,所以尽管它们只相差一个位置时就是满的情况,但也可能是相差整整一圈。 所以若队列的最大尺寸为QueueSize,那么队列满的条件是(rear+1) % QueueSize == front

通用的计算队列长度公式为:(rear - front + QueueSize) % QueueSize

注意:front指针和rear指针后移不能直接使用++,而要使用%:Q->front = (Q->front + 1) % MAXSIZE,因为到达数组尾后需要移动到数组开头。

3 循环队列完整实现

#include "stdafx.h"
#include "stdlib.h"   

#define TRUE 1
#define FALSE 0
#define MAXSIZE 5 /* 存储空间初始分配量 */

typedef int Status;
typedef int QElemType; /* QElemType类型根据实际情况而定,这里假设为int */

/* 循环队列的顺序存储结构 */
typedef struct
{
    QElemType data[MAXSIZE];
    int front;      /* 头指针 */
    int rear;       /* 尾指针,若队列不空,指向队列尾元素的下一个位置 */
}SqQueue;

Status visit(QElemType c)
{
    printf("%d ", c);
    return TRUE;
}

/* 初始化一个空队列Q */
Status InitQueue(SqQueue *Q)
{
    Q->front = 0;
    Q->rear = 0;
    return  TRUE;
}

/* 将Q清为空队列 */
Status ClearQueue(SqQueue *Q)
{
    Q->front = Q->rear = 0;
    return TRUE;
}

/* 若队列Q为空队列,则返回TRUE,否则返回FALSE */
Status QueueEmpty(SqQueue Q)
{
    if (Q.front == Q.rear) /* 队列空的标志 */
        return TRUE;
    else
        return FALSE;
}

/* 返回Q的元素个数,也就是队列的当前长度 */
int QueueLength(SqQueue Q)
{
    return  (Q.rear - Q.front + MAXSIZE) % MAXSIZE;
}

/* 若队列不空,则用e返回Q的队头元素,并返回TRUE,否则返回FALSE */
Status GetHead(SqQueue Q, QElemType *e)
{
    if (Q.front == Q.rear) /* 队列空 */
        return FALSE;
    *e = Q.data[Q.front];
    return TRUE;
}

/* 若队列未满,则插入元素e为Q新的队尾元素 */
Status EnQueue(SqQueue *Q, QElemType e)
{
    if ((Q->rear + 1) % MAXSIZE == Q->front)    /* 队列满的判断 */
        return FALSE;
    Q->data[Q->rear] = e;           /* 将元素e赋值给队尾 */
    Q->rear = (Q->rear + 1) % MAXSIZE;/* rear指针向后移一位置, */
    /* 若到最后则转到数组头部 */
    return  TRUE;
}

/* 若队列不空,则删除Q中队头元素,用e返回其值 */
Status DeQueue(SqQueue *Q, QElemType *e)
{
    if (Q->front == Q->rear)            /* 队列空的判断 */
        return FALSE;
    *e = Q->data[Q->front];             /* 将队头元素赋值给e */
    Q->front = (Q->front + 1) % MAXSIZE;    /* front指针向后移一位置, */
    /* 若到最后则转到数组头部 */
    return  TRUE;
}

/* 从队头到队尾依次对队列Q中每个元素输出 */
Status QueueTraverse(SqQueue Q)
{
    int i;
    i = Q.front;
    while ((i + Q.front) != Q.rear)
    {
        visit(Q.data[i]);
        i = (i + 1) % MAXSIZE;
    }
    printf("\n");
    return TRUE;
}

int main()
{
    Status j;
    int i = 0, l;
    QElemType d;
    SqQueue Q;
    InitQueue(&Q);
    printf("初始化队列后,队列空否?%u(1:空 0:否)\n", QueueEmpty(Q));

    printf("请输入整型队列元素(不超过%d个),-1为提前结束符: ", MAXSIZE - 1);
    do
    {
        /* scanf("%d",&d); */
        d = i + 100;
        if (d == -1)
            break;
        i++;
        EnQueue(&Q, d);
    } while (i<MAXSIZE - 1);

    printf("队列长度为: %d\n", QueueLength(Q));
    printf("现在队列空否?%u(1:空 0:否)\n", QueueEmpty(Q));
    printf("连续%d次由队头删除元素,队尾插入元素:\n", MAXSIZE);
    for (l = 1; l <= MAXSIZE; l++)
    {
        DeQueue(&Q, &d);
        printf("删除的元素是%d,插入的元素:%d \n", d, l + 1000);
        /* scanf("%d",&d); */
        d = l + 1000;
        EnQueue(&Q, d);
    }
    l = QueueLength(Q);

    printf("现在队列中的元素为: \n");
    QueueTraverse(Q);
    printf("共向队尾插入了%d个元素\n", i + MAXSIZE);
    if (l - 2>0)
        printf("现在由队头删除%d个元素:\n", l - 2);
    while (QueueLength(Q)>2)
    {
        DeQueue(&Q, &d);
        printf("删除的元素值为%d\n", d);
    }

    j = GetHead(Q, &d);
    if (j)
        printf("现在队头元素为: %d\n", d);
    ClearQueue(&Q);
    printf("清空队列后, 队列空否?%u(1:空 0:否)\n", QueueEmpty(Q));
    return 0;
}

/*
输出结果:

初始化队列后,队列空否?1(1:空 0:否)
请输入整型队列元素(不超过4个),-1为提前结束符: 队列长度为: 4
现在队列空否?0(1:空 0:否)
连续5次由队头删除元素,队尾插入元素:
删除的元素是100,插入的元素:1001
删除的元素是101,插入的元素:1002
删除的元素是102,插入的元素:1003
删除的元素是103,插入的元素:1004
删除的元素是1001,插入的元素:1005
现在队列中的元素为:
1002 1003 1004 1005
共向队尾插入了9个元素
现在由队头删除2个元素:
删除的元素值为1002
删除的元素值为1003
现在队头元素为: 1004
清空队列后, 队列空否?1(1:空 0:否)
*/

从这一段讲解,大家应该发现,单是顺序存储,若不是循环队列,算法的时间性能是不高的,但循环队列又面临着数组可能会溢出的问题。

原文地址:https://www.cnblogs.com/linuxAndMcu/p/10327803.html

时间: 2024-10-13 17:51:30

数据结构 - 顺序队列的实行(C语言)的相关文章

数据结构 - 链队列的实行(C语言)

数据结构-链队列的实现 1 链队列的定义 队列的链式存储结构,其实就是线性表的单链表,只不过它只能尾进头出而已, 我们把它简称为链队列.为了操作上的方便,我们将队头指针指向链队列的头结点,而队尾指针指向终端结点,如下图所示. 空队列时,front和rear都指向头结点,如下图所示. 链队列的结构为: typedef int QElemType; /* QElemType类型根据实际情况而定,这里假设为int */ typedef struct QNode /* 结点结构 */ { QElemTy

数据结构 - 顺序栈的实行(C语言)

数据结构-顺序栈的实现 1 顺序栈的定义 既然栈是线性表的特例,那么栈的顺序存储其实也是线性表顺序存储的简化,我们简称为顺序栈.线性表是用数组来实现的,对于栈这种只能一头插入删除的线性表来说,用数组哪一端来作为栈顶和栈底比较好? 对,没错,下标为0的一端作为栈底比较好,因为首元素都存在栈底,变化最小,所以让它作栈底. 我们定义一个top变量来指示栈顶元素在数组中的位置,这top就如同中学物理学过的游标卡尺的游标,它可以来回移动,意味着栈顶的top可以变大变小,但无论如何游标不能超出尺的长度.同理

数据结构——顺序队列(sequence queue)

/* sequenceQueue.c */ /* 顺序队列 */ #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #define MAXSIZE 100 /* 顺序循环队列数据结构 */ /* 一个圆圈,front指向队列头,rear指向队列尾 */ /* front -> ... -> rear data[0] -> data[...] -> data[n] */ type

数据结构顺序队列打卡

程序能够运行出来,就是在给队列输入x值的时候不能够输进去,求解! #include<stdio.h>#define maxSize 8typedef int QElemType;typedef struct { QElemType elem[maxSize]; int front,rear;}CircQueue;//初始化void InitQueue (CircQueue &s){ s.front=s.rear=0;} //进队列 int EnQueue (CircQueue &

数据结构-顺序队列

1 #include <iostream> 2 #include <stdlib.h> 3 using namespace std; 4 5 #define maxSize 20 6 7 typedef struct 8 { 9 int data[maxSize]; 10 int front; 11 int rear; 12 }SqQueue; 13 14 void InitQueue(SqQueue &Q) 15 { 16 Q.front=Q.rear=0; 17 } 1

数据结构Java实现07----队列:顺序队列&amp;顺序循环队列、链式队列、顺序优先队列

数据结构Java实现07----队列:顺序队列&顺序循环队列.链式队列.顺序优先队列 一.队列的概念: 队列(简称作队,Queue)也是一种特殊的线性表,队列的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置插入和删除,而队列只允许在其一端进行插入操作在其另一端进行删除操作. 队列中允许进行插入操作的一端称为队尾,允许进行删除操作的一端称为队头.队列的插入操作通常称作入队列,队列的删除操作通常称作出队列. 下图是一个依次向队列中插入数据元素a0,a1,...,an-

数据结构6_顺序队列(循环队列)

本文实现了顺序队列,与链队列不同的是,顺序队列需要考虑一个问题, 问题情况如下, 解决办法:循环队列,当rear到分配的数组空间末尾时,转到数组头 但是当q.rear==q.front时,又如何区分一种是空队列,一种是满队列的情况呢 这里有两种方案 本次代码实现了第一种方法,同时设置了一个技术变量length,稍加改动便可实现第二个方法 代码如下: #include<iostream>using namespace std;//该顺序队列为循环队列,解决队尾指针达到最大值,队列中有空闲单元,但

数据结构--队列实现(顺序队列和链队列)与C++模板

数据结构--队列实现(顺序队列和链队列)与C++模板 一.顺序队列 队列的顺序存储结构称为顺序队列,顺序队列实际上是运算受限的顺序表. ①和顺序表一样,顺序队列用一个向量空间来存放当前队列中的元素. ②由于队列的队头和队尾的位置是变化的,设置两个指针front和rear分别指示队头元素和队尾元素在向量空间中的位置,它们的初值在队列初始化时均应置为0. 注意: ①当头尾指针相等时,队列为空. ②在非空队列里,队头指针始终指向队头元素,尾指针始终指向队尾元素的下一位置.(所以以下循环顺序队列中当队尾

11. C#数据结构与算法 -- 顺序队列

理论基础: 队列(Queue)是插入操作限定在表的尾部而其它操作限定在表的头部进行的线性表.把进行插入操作的表尾称为队尾(Rear),把进行其它操作的头部称为队头(Front). 对列的操作是按照先进先出(First In First Out)或后进后出( Last In Last Out)的原则进行的,因此,队列又称为FIFO表或LILO表. 与栈一样,队列的运算是定义在逻辑结构层次上的,而运算的具体实现是建立在物理存储结构层次上的.因此,把队列的操作作为逻辑结构的一部分,每个操作的具体实现只