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;
}
相关推荐
午彦琳11 分钟前
2026.9.17
数据结构·算法·leetcode
shada27 分钟前
Boost.Process v2 在旧内核上报 `assign: Bad file descriptor`
c++
别动我齐刘海1 小时前
ROS2 Jazzy + C++ 实战路线——基础学习2
c++·人工智能·vscode·python·学习·机器学习·机器人
free-elcmacom2 小时前
C语言指针进阶——指针数组模拟二维数组,以及二级指针到底怎么理解
c语言·visual studio code
朝朝辞暮i2 小时前
C++第 2 课
c++
代码中介商2 小时前
C++ 预约系统实战(三):服务端实现——libevent 事件驱动与业务路由
c++·json·c/s
山下梅子酒2252 小时前
洛谷-入门-B2049
c语言
布莱克6053 小时前
C++中的内存分区详解
c++
All for pursuit.3 小时前
【链表-9】146.LRU缓存
数据结构·c++·算法·leetcode
j7~5 小时前
【C++微服务项目开发脚手架】(接口篇一)gflags + gtest + spdlog 接口学习笔记
c++·学习·gtest·项目开发·spdlog·gflags·c++项目微服务开发脚手架