順序隊列(循環隊列)


概述

隊列(queue)是一種只允許在一端進行插入操作,而在另一端進行刪除操作的線性表。

隊列是一種先進先出(First In First Out)的線性表,簡稱FIFO。

允許插入的一端稱為隊尾,允許刪除的一端稱為隊頭。

因為已經限制了插入和刪除的位置,所以對於隊列,插入和刪除時只需要考慮滿和空兩種狀態。

線性表存儲結構分為順序存儲和鏈式存儲,這里只討論靜態分配的順序存儲結構。

 

約定

為了方便起見,我們約定:

1、初始化建隊列時,令隊頭指針m_nFront和隊尾指針m_nRear等於0,即m_nFront = m_nRear = 0;

2、m_nFront指向隊頭元素的位置,m_nRear指向隊尾元素的下一位。

 

關鍵點

1、順序隊列的假上溢現象

順序隊列的操作分別在隊頭和隊尾兩端進行。在出隊時,隊頭m_nFront和隊尾m_nRear的值都是只增加(向隊列長度m_nCount)靠近;如果僅通過m_nRear == m_nCount來判斷順序隊列是否滿隊,此時可能存在m_nRear已經指向m_nCount,同時m_nFront > 0(已有元素出隊),順序隊列中實際的元素個數遠小於m_nCount而不能做入隊操作的情況,導致元素出隊后的空閑存儲空間永遠無法重用,造成假上溢。如下圖:

 

解決方法

為克服假上溢,可將順序隊列想象為一個首尾相接的環狀空間,稱為循環隊列。在循環隊列中出隊入隊時,頭尾指針仍向前移動進行加1操作,當頭尾指針指向m_nCount時,頭尾指針加1操作的結果重新指向下界0(加1后對m_nCount做取余數運算)。

 

2、判斷隊空和隊滿

想象成循環隊列后,當入隊時,m_nRear向前追趕m_nFront,出隊時,m_nFront向前追趕m_nRear,故存在隊空和隊滿時都有m_nFront == m_nRear的情況,因此無法通過m_nFront == m_nRear來判斷隊空還是隊滿。

解決方法

犧牲存儲空間中的一個存儲單元,使隊空和隊滿的判斷條件不同即可,具體的:

1)出隊時,m_nRear == m_nFront時,表示隊空,此時不能出隊。

2)入隊時,當(m_nRear + 1) % m_nCount == m_nFront時,表示隊滿,此時不能入隊。

 

代碼實現

Queue.h

/*******************************************************
* File Name:Queue.h
* Description:隊列類頭文件,自主實現一個隊列數據結構
* Version:V1.0 
* Author:Mengjia 
* Date:2018-06-02 
* Copyright (C)2018, Mengjia
* Others:自主實現一個隊列數據結構
#pragma once
*******************************************************/
template<class T>
class CQueue
{
private:
    T * m_pData;        //數據指針
    int m_nCount;        //隊列長度
    int m_nFront;        //當前隊列頭部
    int m_nRear;        //當前隊列尾部

public:

    //構造函數
    CQueue(int nCount);

    //析構函數
    ~CQueue()
    {
        delete[] m_pData;
    }

    //入列
    void Enqueue(const T& data);
    //出列
    bool Dequeue(T& data);
    
    //判斷隊滿
    bool isFull()
    {
        return (m_nRear + 1) % m_nCount == m_nFront;
    }
    //判斷隊空
    bool isEmpty()
    {
        return m_nFront == m_nRear;
    }
    
    //遍歷輸出隊列內容
    //注意,如果模板參數傳入的為非基礎數據類型,則無法使用<<進行流的輸出
    void TraverseQueue();

    //清空隊列內容
    void ClearQueue();

    //返回Queue的元素個數,即當前隊列長度
    int QueueLength()
    {
        return (m_nRear - m_nFront + m_nCount) % m_nCount;
    }
};

template<class T>
CQueue<T>::CQueue(int nCount)
{
    m_pData = new T[nCount];
    m_nCount = nCount;
    m_nFront = m_nRear = 0;    //頭尾初始化為0
}

template<class T>
void CQueue<T>::Enqueue(const T& data)
{
    if (!isFull())
    {
        m_pData[m_nRear] = data;
        m_nRear = (m_nRear + 1) % m_nCount;    //隊列尾部前移
    }
}

template<class T>
bool CQueue<T>::Dequeue(T& data)
{
    if (isEmpty())
        return false;
    data = m_pData[m_nFront];
    m_pData[m_nFront] = 0;    //出列后該位置數據清零
    m_nFront = (m_nFront + 1) % m_nCount;    //隊列頭部前移
    return true;
}

template<class T>
void CQueue<T>::TraverseQueue()
{
    int i = m_nFront;
    while (i != m_nRear)
    {
        cout << m_pData[i] << endl;
        i = (i + 1) % m_nCount;
    }
}

template<class T>
void CQueue<T>::ClearQueue()
{
    int i = m_nFront;
    while (i != m_nRear)
    {
        m_pData[i] = 0;
        i = (i + 1) % m_nCount;
    }
    m_nFront = m_nRear = 0;
}

main.cpp

/*******************************************************
* File Name:main.cpp
* Description:用於演示隊列數據結構
* Version:V1.0 
* Author:Mengjia 
* Date:2018-06-02 
* Copyright (C)2018, Mengjia
* Others:
* Blog:
*******************************************************/
#include "Queue.h"
#include <iostream>

using namespace std;

int main()
{
    CQueue<int> queue(6);

    int i = 0;
    while (i < 6)
    {
        queue.Enqueue(i++);
    }
    int data = 0;
    queue.Dequeue(data);
    cout << "The first element of queue: " << data << endl;
    queue.Dequeue(data);
    cout << "The second element of queue: " << data << endl;

    cout << "The Length of queue: " << queue.QueueLength() << endl;

    queue.Enqueue(5);
    queue.Enqueue(6);
    cout << "The Length of queue: " << queue.QueueLength() << endl;
    cout << "Output all elements of queue: " << endl;
    queue.TraverseQueue();

    queue.ClearQueue();
    cout << "The Length of queue: " << queue.QueueLength() << endl;
    system("pause");
    return 0;
}

輸出結果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM