شارك المقالة

الطابور Queue يعمل بمبدأ FIFO: أول عنصر يدخل هو أول عنصر يخرج. ننفذه باستخدام قائمة مترابطة، مع ملكية للرأس ومؤشر مراقبة للنهاية. تصحيح حذف العقد مهم؛ لا يجوز قراءة next أو value عبر مؤشر بعد حذف العقدة التي يشير إليها.

الكود الكامل باستخدام C++17

#include <iostream>
#include <memory>
#include <optional>
#include <utility>

class LinkedQueue {
    struct Node {
        int value;
        std::unique_ptr<Node> next;
        explicit Node(int v) : value(v) {}
    };
    std::unique_ptr<Node> front;
    Node* rear = nullptr; // Non-owning observer; front owns the chain.
public:
    LinkedQueue() = default;
    LinkedQueue(const LinkedQueue&) = delete;
    LinkedQueue& operator=(const LinkedQueue&) = delete;
    bool empty() const { return !front; }
    void enqueue(int value) {
        auto node = std::make_unique<Node>(value);
        Node* newRear = node.get();
        if (rear) rear->next = std::move(node);
        else front = std::move(node);
        rear = newRear;
    }
    std::optional<int> peek() const {
        if (!front) return std::nullopt;
        return front->value;
    }
    std::optional<int> dequeue() {
        if (!front) return std::nullopt;
        auto old = std::move(front);
        front = std::move(old->next);
        if (!front) rear = nullptr;
        return old->value;
    }
    ~LinkedQueue() { while (!empty()) dequeue(); }
};

int main() {
    LinkedQueue queue;
    queue.enqueue(10);
    queue.enqueue(20);
    while (auto value = queue.dequeue()) std::cout << *value << ' ';
    queue.enqueue(30); // Reuse after removing the last node.
    if (auto value = queue.dequeue()) std::cout << *value << '\n';
    std::cout << "Empty: " << queue.empty() << '\n';
}

وظيفة front وrear

يمثل front بداية القائمة، ويشير rear إلى آخر عقدة دون امتلاكها. تضيف enqueue عند النهاية، وتحذف dequeue من البداية؛ كلتا العمليتين O(1). إدخال 10 ثم 20 يخرجهما بالترتيب نفسه، ثم يمكن إدخال 30 وإخراجه حتى بعد فراغ الطابور.

حذف آخر عنصر بأمان

عندما تحذف dequeue العقدة الأخيرة تصبح front فارغة، ولذلك نضبط rear إلى nullptr. بقاء rear على عنوان عقدة حُذفت يسبب كتابة غير صالحة عند الإضافة التالية. نستخدم متغير old للاحتفاظ بالعقدة إلى أن ننقل next وننسخ القيمة، ثم تتولى unique_ptr تحريرها.

الاختبارات الأساسية

اختبر الحذف من طابور فارغ، وإضافة عنصر واحد وحذفه، ثم الإضافة من جديد. تعيد الدوال optional بدل إنهاء البرنامج أو إرجاع مؤشر معلّق. destructor يزيل العقد المتبقية على مراحل. في التطبيقات يمكن استخدام std::queue، بينما هذا التنفيذ يشرح الملكية وروابط القائمة والفرق عن Stack.

ترجمة المثال وتشغيله

احفظ المثال في ملف main.cpp واختر معيار C++17 في محررك. مع GCC أو Clang يمكنك الترجمة بالأمر g++ -std=c++17 -Wall -Wextra -pedantic main.cpp -o main ثم تشغيل الملف الناتج. ترجم كل مثال كبرنامج مستقل؛ لا تجمع دوال main من دروس مختلفة في ملف واحد.

الصور والفيديو من الشرح السابق

الكود النصي أعلاه هو النسخة المصححة؛ قد تختلف المواد المرئية السابقة في أسماء المتغيرات أو طريقة التشغيل.

شاهد أيضًا
مقالات ذات صلة
🚫 مانع الإعلانات مفعل

يجب إيقاف مانع الإعلانات لاستكمال تصفح الموقع