C/C++数据结构之用链表实现队列

概述

在前一篇文章中,我们已经用数组实现了队列。在本篇文章中,我们将使用链表来实现队列。使用链表的优点是:动态增长,扩容时更加平滑。缺点是:略微复杂,需要额外管理所有节点。队列相关的操作,仍然是下面6个接口。

Enqueue:向队尾添加一个元素。

Dequeue:从队首移除顶部元素,并返回该元素。

Front:查看队首元素,但不移除它。

Rear:查看队尾元素,但不移除它。

IsEmpty:检查队列是否为空。

Size:获取队列中元素的数量。

实现原理

我们使用一个带头指针和尾指针的单链表来实现队列。其中,头指针对应链表的头部,尾指针对应链表的尾部。入队操作在尾部插入新节点,出队操作从头部删除节点。所有操作均维护头指针和尾指针的正确性,确保队列行为符合FIFO规则。

在下面队列CLinkedListQueue的实现中,我们声明了两个成员变量m_pFront和m_pRear。m_pFront代表队首,m_pRear代表队尾。

cpp 复制代码
class CLinkedListQueue
{
public:
    CLinkedListQueue();
    ~CLinkedListQueue();

    void Enqueue(int nValue);
    int Dequeue();
    int Front();
    int Rear();
    bool IsEmpty();
    int Size();

private:
    struct Node
    {
        int nData;
        Node* pNext;
    };

    Node* m_pFront;
    Node* m_pRear;
};

Enqueue操作

入队就是在链表的尾部插入一个新节点,详细步骤如下。

1、创建一个新节点。

2、如果队列为空,将m_pFront和m_pRear都指向新节点。

3、如果队列非空,将当前尾节点m_pRear的pNext指向新节点pNode,并更新尾指针为pNode。

具体如何实现,可参考下面的示例代码。

cpp 复制代码
void CLinkedListQueue::Enqueue(int nValue)
{
    Node* pNode = new Node();
    pNode->nData = nValue;
    pNode->pNext = NULL;

    if (IsEmpty())
    {
        m_pFront = m_pRear = pNode;
    }
    else
    {
        m_pRear->pNext = pNode;
        m_pRear = pNode;
    }
}

Dequeue操作

出对就是删除链表头部节点,并返回其值,详细步骤如下。

1、如果队列为空,抛出异常。

2、取出队首节点的值,保存为临时变量。

3、将队首指针更新为下移一位后的指针,如果新的队首指针为空,则将队尾指针也设置为空。

4、释放旧节点的内存。

5、返回上面的临时变量。

具体如何实现,可参考下面的示例代码。

cpp 复制代码
int CLinkedListQueue::Dequeue()
{
    if (IsEmpty())
    {
        throw underflow_error("queue is empty");
    }

    Node* pTemp = m_pFront;
    int nValue = pTemp->nData;

    m_pFront = m_pFront->pNext;
    if (m_pFront == NULL)
    {
        m_pRear = NULL;
    }

    delete pTemp;
    return nValue;
}

完整实现

Front操作、Rear操作、IsEmpty操作、Size操作都比较简单,这里就不再赘述了。CLinkedListQueue类的完整实现,可参考下面的示例代码。

cpp 复制代码
#include <iostream>
#include <stdexcept>

using namespace std;

class CLinkedListQueue
{
public:
    CLinkedListQueue();
    ~CLinkedListQueue();

    void Enqueue(int nValue);
    int Dequeue();
    int Front();
    int Rear();
    bool IsEmpty();
    int Size();

private:
    struct Node
    {
        int nData;
        Node* pNext;
    };

    Node* m_pFront;
    Node* m_pRear;
};

CLinkedListQueue::CLinkedListQueue() : m_pFront(NULL), m_pRear(NULL)
{
    NULL;
}

CLinkedListQueue::~CLinkedListQueue()
{
    while (!IsEmpty())
    {
        Dequeue();
    }
}

void CLinkedListQueue::Enqueue(int nValue)
{
    Node* pNode = new Node();
    pNode->nData = nValue;
    pNode->pNext = NULL;

    if (IsEmpty())
    {
        m_pFront = m_pRear = pNode;
    }
    else
    {
        m_pRear->pNext = pNode;
        m_pRear = pNode;
    }
}

int CLinkedListQueue::Dequeue()
{
    if (IsEmpty())
    {
        throw underflow_error("queue is empty");
    }

    Node* pTemp = m_pFront;
    int nValue = pTemp->nData;

    m_pFront = m_pFront->pNext;
    if (m_pFront == NULL)
    {
        m_pRear = NULL;
    }

    delete pTemp;
    return nValue;
}

int CLinkedListQueue::Front()
{
    if (IsEmpty())
    {
        throw underflow_error("queue is empty");
    }

    return m_pFront->nData;
}

int CLinkedListQueue::Rear()
{
    if (IsEmpty())
    {
        throw underflow_error("queue is empty");
    }

    return m_pRear->nData;
}

bool CLinkedListQueue::IsEmpty()
{
    return m_pFront == NULL;
}

int CLinkedListQueue::Size()
{
    int nSize = 0;
    Node* pTemp = m_pFront;
    while (pTemp != NULL)
    {
        ++nSize;
        pTemp = pTemp->pNext;
    }

    return nSize;
}

int main()
{
    CLinkedListQueue q;

    q.Enqueue(66);
    q.Enqueue(77);
    q.Enqueue(88);

    cout << "Front element: " << q.Front() << endl;
    cout << "Rear element: " << q.Rear() << endl;
    cout << "Dequeue: " << q.Dequeue() << endl;
    cout << "Dequeue: " << q.Dequeue() << endl;
    cout << "Current size: " << q.Size() << endl;
    cout << "Is empty: " << (q.IsEmpty() ? "True" : "False") << endl;
    return 0;
}
相关推荐
Horn Still Sounds12 分钟前
Linux系统编程进阶:进程回收、程序替换与多线程并发模型
linux·运维·服务器·c语言
渡我白衣1 小时前
深入理解 Transformer:Transformer 究竟是什么?
java·linux·开发语言·c++·人工智能·深度学习·transformer
xu_wenming8 小时前
嵌入式软件架构中的6种解耦艺术
c语言·驱动开发·嵌入式硬件·架构
「QT(C++)开发工程师」9 小时前
C++ 11 常用for循环
开发语言·c++
我还记得那天10 小时前
0 初识C++
开发语言·c++
「QT(C++)开发工程师」12 小时前
C++ std::move 详解
开发语言·c++
DevHub12 小时前
CANopen 教程:STM32 实现 CANopen 从站,3 个回调替代手写对象字典
c语言·驱动开发·stm32·单片机·嵌入式硬件·mcu
不灭的黄金瞳12314 小时前
C语言手写顺序表
c语言·开发语言·数据结构
豆沙沙包?14 小时前
C++~~~set容器、map容器(p57-P69)
开发语言·c++