How to create a doubly linked list in C++

1 Answer

0 votes
#include <iostream>
#include <random>

/*
 * A minimal doubly‑linked list node.
 * This is similar to your C version, but now it is a base class.
 * User-defined data types will inherit from DNode.
 */
struct DNode {
    DNode* prev = nullptr;
    DNode* next = nullptr;
};

/*
 * A generic doubly‑linked list using sentinel head/tail nodes.
 * This class manages memory for the sentinel nodes only.
 * User nodes are owned by the caller (like std::list does).
 */
class DList {
public:
    DList() {
        // Initialize sentinel links
        head.next = &tail;
        tail.prev = &head;
    }

    bool empty() const {
        return head.next == &tail;
    }

    // Return first real node or nullptr
    DNode* front() {
        return empty() ? nullptr : head.next;
    }

    // Return last real node or nullptr
    DNode* back() {
        return empty() ? nullptr : tail.prev;
    }

    // Insert node at front
    void push_front(DNode* n) {
        insert_after(&head, n);
    }

    // Insert node at back
    void push_back(DNode* n) {
        insert_before(&tail, n);
    }

    // Remove and return first node
    DNode* pop_front() {
        if (empty()) return nullptr;
        return remove_node(head.next);
    }

    // Remove and return last node
    DNode* pop_back() {
        if (empty()) return nullptr;
        return remove_node(tail.prev);
    }

    // Insert n after node r
    void insert_after(DNode* r, DNode* n) {
        DNode* s = r->next;
        n->prev = r;
        n->next = s;
        r->next = n;
        s->prev = n;
    }

    // Insert n before node r
    void insert_before(DNode* r, DNode* n) {
        insert_after(r->prev, n);
    }

    // Remove node n from list
    DNode* remove_node(DNode* n) {
        DNode* p = n->prev;
        DNode* s = n->next;
        p->next = s;
        s->prev = p;
        return n;
    }

private:
    DNode head;  // sentinel head
    DNode tail;  // sentinel tail
};

/*
 * A user-defined node that stores actual data.
 * It inherits from DNode so it can be inserted into DList.
 */
struct IntNode : public DNode {
    int value;
};

/*
 * Print list forward
 */
void print_forward(DList& list) {
    std::cout << "Forward: ";
    for (DNode* n = list.front(); n != nullptr && n->next != nullptr; n = n->next) {
        if (n->next == nullptr) break; // safety
        IntNode* m = static_cast<IntNode*>(n);
        std::cout << m->value << " ";
        if (n->next->next == nullptr) break; // reached tail sentinel
    }
    std::cout << "\n";
}

/*
 * Print list backward
 */
void print_backward(DList& list) {
    std::cout << "Backward: ";
    for (DNode* n = list.back(); n != nullptr && n->prev != nullptr; n = n->prev) {
        IntNode* m = static_cast<IntNode*>(n);
        std::cout << m->value << " ";
        if (n->prev->prev == nullptr) break; // reached head sentinel
    }
    std::cout << "\n";
}

int main() {
    // C++ random generator
    std::mt19937 rng(std::random_device{}());
    std::uniform_int_distribution<int> dist(0, 99);

    DList list;

    // Add 5 random nodes at tail
    for (int i = 0; i < 5; i++) {
        auto* n = new IntNode;
        n->value = dist(rng);   // idiomatic random
        list.push_back(n);
    }

    std::cout << "Added 5 nodes\n";
    print_forward(list);
    print_backward(list);

    // Insert at head
    auto* h = new IntNode;
    h->value = 999;
    list.push_front(h);

    std::cout << "Inserted 999 at head\n";
    print_forward(list);

    // Remove head
    auto* removed = static_cast<IntNode*>(list.pop_front());
    std::cout << "Removed head: " << removed->value << "\n";
    delete removed;

    print_forward(list);

    // Remove all nodes from tail
    while (!list.empty()) {
        auto* n = static_cast<IntNode*>(list.pop_back());
        std::cout << "Removed tail: " << n->value << "\n";
        delete n;
    }
}



/*
run:

Added 5 nodes
Forward: 63 30 84 88 47 
Backward: 47 88 84 30 63 
Inserted 999 at head
Forward: 999 63 30 84 88 47 
Removed head: 999
Forward: 63 30 84 88 47 
Removed tail: 47
Removed tail: 88
Removed tail: 84
Removed tail: 30
Removed tail: 63

*/

 



answered Apr 15 by avibootz
...