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 小时前
CMake 034:生成器表达式:解耦构建时序、精简分支逻辑的终极利器
c++·cmake
见过夏天1 天前
C++ 基础入门完全指南
c++
CSharp精选营2 天前
关系型 vs 非关系型:从原理到选型,一文搞定数据库核心分类
数据结构·nosql·关系型数据库·非关系型数据库·技术选型
用户805533698032 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
BadBadBad__AK3 天前
线段树维护区间 k 次方和
c++·数学·算法·stl
卷无止境3 天前
Eigen 库如何借助 OpenMP 加速计算
c++·后端
卷无止境3 天前
OpenMPI、MPICH 与 OpenMP:关系、核心概念与架构全解
c++·后端
郝学胜_神的一滴4 天前
CMake 30:循环语法全解|foreach_while双循环精讲、迭代技巧与实战避坑指南
c++·cmake
刘马想放假5 天前
Modbus 全栈技术解析:TCP、RTU、ASCII、RTU over TCP
数据结构·网络协议
北域码匠6 天前
冒泡排序太慢?鸡尾酒排序双向优化,原生 C# 零第三方库完整代码
数据结构·排序算法·泛型·c# 算法·鸡尾酒排序·原生 c# 开发·冒泡排序优化·嵌入式算法