zoukankan      html  css  js  c++  java
  • 数据结构:队列的顺序存储结构(循环队列)

    队列的定义:


    队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表

    队列的抽象数据类型:

    ADT 队列(Queue)
    Data
        同线性表,元素具有相同的类型,相邻元素具有前驱和后继关系。
    Operation
        InitQueue(*Q):        初始化操作,建立一个空队列。
        DestroyQueue(*Q):     若队列Q存在,则销毁它。
        ClearQueue(*Q):       将队列清空。
        QueueEmpty(Q):        判断队列是否为空。
        GetHead(Q,*e):        若队列存在且非空,用e返回Q的队头元素。
        EnQueue(*Q,e):        若队列Q存在,插入新元素e到队列Q中并成为队尾元素。
        DeQueue(*Q,*e):       删除队列中的队头元素,并用e返回。
        QueueLength(Q):       返回队列Q的元素的个数。
    
    endADT

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

    队列的顺序存储结构同线性表的顺序存储结构存在着同样的问题,队头出队列要后面的元素依次向前移动,时间复杂度为O(n)。

    image

    因为队列的每次删除元素都是从队头,所以每次删除都有大量的元素要移动,这样算法的效率很不好。于是改进一下,队头不一定要在数组的下标为0的位置。也就是说删除一个元素,仅需要把队头指针向后移动一次。

    image

    同时让front指针指向队头元素,rear指针指向队尾元素的下一个位置。这样当front等于rear时,队列就为空。

    但是此时还有问题,会有假溢出的现象。

    image

    解决这种问题的办法就是循环队列。让上面的队尾指针rear指向数组的下标0位置。

    队列的这种头尾相接的顺序存储结构称为循环队列

    但是还存在一个问题:当队列空或者满的时候都是front==rear。那么这个要怎么判断呢?

    imageimage

    (1)设置一个标志变量flag,当fron==rear且flag==0时,队列为空;当front==rear且flag==1时队列满。

    (2)当队列为空时,条件就是front==rear,当队列满时修改条件,保留一个元素空间。也就是说队列满时,数组还有一个空闲单元。

    image

    这里假设队列的最大尺寸为QueueSize,所以队列满的条件是(rear+1)%QueueSize == front

    队列的长度为(rear-front+QueueSize)%QueueSize

    循环队列代码实现:


    #include <iostream>
    #include <stdlib.h>
    using namespace std;
    #define QueueSize 20
    
    /********************************
    *
    *    循环队列的顺序存储结构代码
    *
    ********************************/
    typedef int QElemType;
    typedef struct 
    {
        QElemType data[QueueSize];
        int front;
        int rear;
    }SqQueue;
    
    /********************************
    *
    *    循环队列的操作函数实现代码
    *
    ********************************/
    /*初始化一个队列*/
    bool InitQueue(SqQueue *Q)
    {
        Q->front = 0;
        Q->rear = 0;
    
        return true;
    }
    /*返回Q的元素的个数,也就是队列的当前长度*/
    int QueueLength(SqQueue Q)
    {
        return (Q.rear-Q.front + QueueSize) % QueueSize;
    }
    /*若队列未满,插入元素e为Q的新队尾元素*/
    bool EnQueue(SqQueue *Q, QElemType e)
    {
        if((Q->rear + 1) % QueueSize == Q->front)
        {
            return false;
        }
        cout << "EnQueue Item " << e << endl;
        Q->data[Q->rear] = e;
        Q->rear = (Q->rear + 1) % QueueSize;
    
        return true;
    }
    /*若队列不空,删除Q中队头的元素,用e返回其值*/
    bool DeQueue(SqQueue *Q, QElemType *e)
    {
        if(Q->front == Q->rear)
        {
            return false;
        }
        
        *e = Q->data[Q->front];
        Q->front = (Q->front + 1) % QueueSize;
        cout << "DeQueue Item " << *e << endl;
    
        return true;
    }
    /*将队列清空*/
    bool ClearQueue(SqQueue *Q)
    {
        Q->front = 0;
        Q->rear = 0;
        return true;
    }
    /*判断队列是否为空*/
    bool IsEmptyQueue(SqQueue Q)
    {
        return Q.front == Q.rear;
    }
    /*返回队头元素*/
    bool GetTop(SqQueue Q, QElemType *e)
    {
        if(IsEmptyQueue(Q))
        {
            return true;
        }
    
        *e = Q.data[Q.front];
        cout << "Get Top Item:" << *e << endl;
    
        return true;
    }
    /*遍历队列中的各个元素*/
    bool QueueTraverse(SqQueue Q)
    {
        if(IsEmptyQueue(Q))
        {
            return false;
        }
        cout << "Queue Traverse ..." << endl;
    
        int count =  (Q.rear - Q.front + QueueSize) % QueueSize;
        for(int i = Q.front; i < Q.front + count; i++)
        {
            cout << Q.data[i] << ' '; 
        }
        cout << endl;
    
        return true;
    }
    
    void main(void)
    {
        SqQueue sq;
        InitQueue(&sq);
        for(int i = 0; i < 10; i++)
        {
            EnQueue(&sq, i);
        }
        QueueTraverse(sq);
    
        if(!IsEmptyQueue(sq))
        {
            cout << "Queue Length: " << QueueLength(sq) << endl;
        }
    
        int result;
        GetTop(sq, &result);
        DeQueue(&sq, &result);
        DeQueue(&sq, &result);
    
        QueueTraverse(sq);
    
        for(int i = 0; i < 11; i++)
        {
            EnQueue(&sq, i);
        }
        GetTop(sq, &result);
        QueueTraverse(sq);
    
        system("pause");
    }

    执行结果:

    image

    单是顺序存储,若不是循环队列,算法的时间性能是不高的,但循环队列又面临着数组可能溢出的问题,所以还是要研究一下不需要担心队列长度的链式存储结构。

  • 相关阅读:
    python测试开发django186.使用 jquery 的 .val() 无法获取input框的输入值(已解决) 上海
    2022年第 10 期《python接口web自动化+测试开发》课程,2月13号开学! 上海
    python测试开发django185.bootstraptable 后端搜索功能实现(queryParams) 上海
    python测试开发django184.bootstraptable 前端分页搜索相关配置 上海
    python测试开发django181.自定义过滤器(除法取余) 上海
    python测试开发django180.dockercompose部署django+mysql环境 上海
    python测试开发django183.bootstrapformvalidation重置校验的方法 上海
    pytest文档79 内置 fixtures 之 cache 写入和读取缓存数据 上海
    python测试开发django182.jQuery重置form表单 上海
    golang interface用法
  • 原文地址:https://www.cnblogs.com/stemon/p/4283945.html
Copyright © 2011-2022 走看看