隊列 - 從零開始實現by C++


參考鏈接:數據結構探險—隊列篇

數據結構太重要了,不學好是沒法進行軟件開發的。

C++寫數據結構基本套路:一個.h文件寫該數據結構類的接口;一個.cpp文件寫接口的具體實現;一個main.cpp用於測試。

隊列


隊列的模型

想象一下現實生活中的隊列,排隊先入先出,不允許插隊,隊頭先出,隊尾進入。(應用:營業廳自動排號機)

隊列的編程實現方式

環形隊列,數組實現,靜態的,事先確定隊列容量,人為取余,循環利用數組資源。

普通隊列, 鏈表實現,動態的,有點浪費,因為插入刪除只在隊列頭尾進行

隊列的基本元素

要操縱隊列,必須要有一個數組(指針),隊列長度,隊列容量;然后用隊列頭和隊列尾操縱隊列。

環形隊列中隊列頭和隊列尾到底意味着什么?對尾指向最后一個元素的下一個位置。

隊列的基本操作

創建隊列,銷毀隊列,清空隊列,隊列判空,隊列判滿,隊列長度;元素入隊,元素出對,遍歷隊列

基本操作的實現

創建隊列:構造函數實現,函數參數為隊列容量;此步需要完成的任務:形成數組實體,即分配內存,將一些隊列基本元素初始化。

銷毀隊列:析構函數實現,釋放內存,指針置空。

清空隊列:指針不動,基本元素初始化

隊列判空:通過長度判斷

隊列判滿:通過長度和容量判斷

隊列長度:直接返回

元素入隊:判斷能否插入,能則插入,更新隊列基本信息(技巧)

元素出對:判斷是否有東西可以刪除,更新隊列基本信息

遍歷隊列:循環,從頭到尾,遍歷(輸出)

大部分的操作都是針對隊列基本元素的,會利用和改變它。(所以用C++其實是簡化了,只需考慮類內數據元素)

寫一個大型的數據結構很難,很容易就會出現某些細小的錯誤,如果無法控制這些細小的錯誤,那等程序大起來之后,就很難很難找錯和調試了。

C++實現步驟

  • 首先,把上面的流程走一遍,做到心中有數。
  • 設計隊列的接口(建議寫在一個單獨文檔里,以便隨時查閱),先不談具體實現;(照着抄很容易,關鍵要會默寫)
  • 實現,核心功能,創建,插入,刪除,遍歷顯示,調試成功
  • 補充其他核心功能

代碼要寫好,還真是太難了,首先要正確的命名,其次大小寫還不能搞錯,在使用的時候還要一一對應。

函數的返回值、函數名、參數等等,都不允許有錯誤。(很難一次性寫好,在實現時慢慢修正)

初次親手敲代碼的體會:隊列的代碼量確實很少,接口20多行;實現80多行,測試20多行,根本就不算多;但是寫起來還是感覺很難,之前敲書本上的單個例題,感覺還沒什么難度;隊列元素太多,基本的5個元素,操作太多,9個基本操作,操作之間部分依賴;我對C++的語法也不算太熟悉,有些卡頓;東西太多,太雜,名稱太長,導致我眼花繚亂。

課程筆記

這是之前C++的進階課,數據結構:一群數據以及數據之間的關系(集合+關系),數據結構是前人經驗的總結,所以你學習借鑒就好了,不要鑽牛角尖。

隊列是先入先出的數學模型,隊列中很少用到位序,因為只能對首尾進行操作,載入元素默認實在隊尾,刪除元素默認是在隊頭。

隊列分為普通隊列和環形隊列

普通隊列:分兩種情況,一是隊頭離開,后面全部前移;二是隊頭離開,不移,往后繼續排,這兩種結果都不好

環形隊列:充分利用資源,也不犧牲效率;隊頭隊尾重疊只有兩種情況,要么為空,要么為滿。

隊列的C和C++實現方式是大為不同的

在C++中,隊列被寫成了類,每一個具體隊列都是該類的實例;而C語言中,只是簡單定義了個結構體,C語言函數的參數中一定要含有隊列的地址,而C++因為寫在了類中,則不用傳參數。

標准C++代碼

#pragma once
//MyQueue.h
//環形隊列C++實現
class MyQueue
{
public:
    MyQueue(int queueCapacity);        //InitQueue(&Q)創建隊列
    virtual ~MyQueue();                //DestroyQueue(&Q)銷毀隊列
    void ClearQueue();                //ClearQueue(&Q)清空隊列
    bool QueueEmpty() const;        //QueueEmpty(&Q)判空隊列
    int QueueLength() const;        //QueueLength(Q)隊列長度
    bool QueueFull() const;

    bool EnQueue(int element);        //EnQueue(&Q, element)新元素入隊
    bool DeQueue(int &element);        //DeQueue(&Q, &element)首元素出隊
    void QueueTraverse();            //QueueTraverse(Q, visit())遍歷隊列
private:
    int *m_pQueue;                    //隊列數組數組
    int m_iQueueLen;                //隊列元素個數
    int m_iQueueCapacity;            //隊列數組容量

    int m_iHead;
    int m_iTail;
};
//MyQueue.cpp
#include"MyQueue.h"
#include<iostream>
using namespace std;

MyQueue::MyQueue(int queueCapacity)
{
    m_iQueueCapacity = queueCapacity;
    m_iHead = 0;
    m_iTail = 0;
    m_iQueueLen = 0;
    m_pQueue = new int[m_iQueueCapacity];
}

MyQueue::~MyQueue()
{
    delete[]m_pQueue;
    m_pQueue = nullptr;
}

void MyQueue::ClearQueue()
{
    m_iHead = 0;
    m_iTail = 0;
    m_iQueueLen = 0;
}

bool MyQueue::QueueEmpty() const
{
    if (m_iQueueLen == 0)
        return true;
    else
        return false;
}

bool MyQueue::QueueFull() const
{
    if (m_iQueueLen == m_iQueueCapacity)
        return true;
    else
        return false;
}

int MyQueue::QueueLength() const
{
    return m_iQueueLen;
}

bool MyQueue::EnQueue(int element)
{
    if (QueueFull())
        return false;
    else
    {
        m_pQueue[m_iTail] = element;
        m_iTail++;
        m_iTail = m_iTail % m_iQueueCapacity;
        m_iQueueLen++;
        return true;
    }
}

bool MyQueue::DeQueue(int &element)
{
    if (QueueEmpty())
        return false;
    else
    {
        element = m_pQueue[m_iHead];
        m_iHead++;
        m_iHead = m_iHead % m_iQueueCapacity;
        m_iQueueLen--;
        return true;
    }
}

void MyQueue::QueueTraverse()
{
    for (int i = m_iHead; i < m_iQueueLen + m_iHead; i++)
    {
        cout << m_pQueue[i%m_iQueueCapacity] << endl;
    }
}
//demo.cpp
#include<iostream>
#include"MyQueue.h"
using namespace std;

int main()
{
    MyQueue *p = new MyQueue(4);
    p->EnQueue(1);
    p->EnQueue(0);
    p->EnQueue(11);
    p->QueueTraverse();
    p->ClearQueue();
    cout << "after clear: " << endl;
    p->QueueTraverse();
    if (p->QueueEmpty())
        cout << "Empty queue" << endl;
    else
        cout << "Not Empty" << endl;
    p->EnQueue(5);
    p->EnQueue(15);
    p->EnQueue(25);
    cout << p->QueueLength() << endl;
    int tmp;
    p->DeQueue(tmp);
    cout << "tmp is " << tmp << endl;
    cout << p->QueueLength() << endl;
    return 0;
}

 

實際應用

節點的數據可以是任意類型的數據,ElemType為Customer

//Customer.h
#pragma once
#include <string>
using namespace std;

class Customer
{
public:
    Customer(string name = "", int age = 0);
    void printInfo() const;
private:
    string m_strName;
    int m_iAge;
};
//Customer.cpp
#include<iostream>
#include"Customer.h"
using namespace std;

Customer::Customer(string name, int age)
{
    m_strName = name;
    m_iAge = age;
}

void Customer::printInfo() const
{
    cout << "Name: " << m_strName << endl;
    cout << "Age: " << m_iAge << endl;
    cout << "=================" << endl;
}
//demo.cpp
#include<iostream>
#include"MyQueue.h"
using namespace std;

int main()
{
    MyQueue *p = new MyQueue(4);
    Customer c1("zhangsan", 20);
    Customer c2("lisi", 30);
    Customer c3("wangwu", 24);

    p->EnQueue(c1);
    p->EnQueue(c2);
    p->EnQueue(c3);

    p->QueueTraverse();

    cout << endl;
    Customer c4;
    p->DeQueue(c4);
    cout << "this is c4: " << endl;
    c4.printInfo();

    cout << "this is QueueTraverse: " << endl;
    p->QueueTraverse();
    return 0;
}

 

使用C++模板寫一個隊列

 

比較C和C++實現的不同


免責聲明!

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



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