A shared pointer is a smart pointer that can manage the lifetime of an object by keeping track of how many pointers are pointing to it. In a doubly linked list, a shared pointer can be used to manage the memory of the nodes.

In a doubly linked list, each node has two pointers: a next pointer and a previous pointer. The next pointer points to the next node in the list, and the previous pointer points to the previous node in the list. When a new node is created, a shared pointer can be used to manage the memory of the node.

The shared pointer can be created using the “std::shared_ptr” class in C++. The constructor of the shared pointer takes a pointer to the node as an argument. The shared pointer will then keep track of how many pointers are pointing to the node. When there are no more pointers pointing to the node, the shared pointer will automatically delete the node.

In Python, there is no built-in shared pointer class, but you can use the “weakref” module to create weak references to objects. A weak reference is a reference to an object that does not increase its reference count, which means that the object can still be garbage-collected even if there are weak references to it. This is similar to the behavior of a shared pointer.

In Java, the equivalent of a shared pointer is the “java.lang.ref.WeakReference” class, which allows you to create weak references to objects. Java also has a “java.lang.ref.SoftReference” class, which behaves like a shared pointer but may be cleared if the system needs more memory.

In Ruby, you can use the “WeakRef” class from the “weakref” module to create weak references to objects, similar to Python’s “weakref” module. Additionally, Ruby has a garbage collector that automatically manages memory, so it is less common to need to create shared pointers or similar constructs explicitly.

Using a shared pointer in a doubly linked list can help prevent memory leaks and make it easier to manage the lifetime of the nodes.

Create a linked list node

// Define the node structure for the doubly linked list
struct Node {
    int value;
    shared_ptr<Node> next;
    shared_ptr<Node> prev;
};

This defines the node structure for the doubly linked list, which has an integer value and two shared pointers to the next and previous nodes in the list.

Define the doubly linked list class

// Define the doubly linked list class
class DoublyLinkedList {
private:
    shared_ptr<Node> head;
    shared_ptr<Node> tail;
public:
    // Constructor
    DoublyLinkedList() {
        head = nullptr;
        tail = nullptr;
    }

This defines the doubly linked list class and declares two shared pointers, head and tail, to the first and last nodes in the list. The constructor initializes these pointers to nullptr.

Add a node to the front of the list

// Add a node to the front of the list
void push_front(int value) {
    auto new_node = make_shared<Node>();
    new_node->value = value;
    new_node->next = head;
    if (head != nullptr) {
        head->prev = new_node;
    }
    head = new_node;
    if (tail == nullptr) {
        tail = head;
    }
}

This function adds a new node to the front of the list with the given value. It creates a new shared pointer to a new node using the make_shared function, sets the node’s value and next pointer to the head of the list, and updates the head pointer to point to the new node. If the list was empty before this operation, the tail pointer is also updated to point to the new node.

See also  Reverse a doubly linked list using recursion

Add a node to the end of the list

// Add a node to the end of the list
void push_back(int value) {
    auto new_node = make_shared<Node>();
    new_node->value = value;
    new_node->prev = tail;
    if (tail != nullptr) {
        tail->next = new_node;
    }
    tail = new_node;
    if (head == nullptr) {
        head = tail;
    }
}

This function adds a new node to the end of the list with the given value. It creates a new shared pointer to a new node using the make_shared function, sets the node’s value and previous pointer to the tail of the list, and updates the tail pointer to point to the new node. If the list was empty before this operation, the head pointer is also updated to point to the new node.

Remove the first node in the list

// Remove the first node in the list
void pop_front() {
    if (head != nullptr) {
        auto old_head = head;
        head = head->next;
        if (head != nullptr) {
            head->prev = nullptr;
        } else {
            tail = nullptr;
        }
        // Decrement the reference count of the old head node
        old_head.reset();
    }
}

This function removes the first node in the list. It updates the head pointer to point to the next node in the list, updates the previous pointer of the new head node to nullptr, and decrements the reference count of the old head node to allow it to be garbage-collected.

Remove the last node in the list

// Remove the last node in the list
void pop_back() {
    if (tail != nullptr) {
        auto old_tail = tail;
        tail = tail->prev;
        if (tail != nullptr) {
            tail->next = nullptr;
        } else {
            head = nullptr;
        }
        // Decrement the reference count of the old tail node
        old_tail.reset();
    }
}

This function removes the last node in the list. It updates the tail pointer to

point to the previous node in the list, updates the next pointer of the new tail node to nullptr, and decrements the reference count of the old tail node to allow it to be garbage-collected.

Get the value of the first node in the list

// Get the value of the first node in the list
int front() {
    if (head != nullptr) {
        return head->value;
    } else {
        // Throw an exception or return a default value if the list is empty
    }
}

This function returns the value of the first node in the list. If the list is empty, it can throw an exception or return a default value.

Get the value of the last node in the list

// Get the value of the last node in the list
int back() {
    if (tail != nullptr) {
        return tail->value;
    } else {
        // Throw an exception or return a default value if the list is empty
    }
}

This function returns the value of the last node in the list. If the list is empty, it can throw an exception or return a default value.

Insert a new node at the specified position in the list

// Insert a new node at the specified position in the list
void insert(int value, int pos) {
    if (pos < 0) {
        // Throw an exception or handle the error
    } else if (pos == 0) {
        push_front(value);
    } else {
        auto curr = head;
        int i = 0;
        while (curr != nullptr && i < pos - 1) {
            curr = curr->next;
            i++;
        }
        if (curr != nullptr) {
            auto new_node = make_shared<Node>();
            new_node->value = value;
            new_node->prev = curr;
            new_node->next = curr->next;
            if (curr->next != nullptr) {
                curr->next->prev = new_node;
            } else {
                tail = new_node;
            }
            curr->next = new_node;
        } else {
            // Throw an exception or handle the error
        }
    }
}

The insert function inserts a new node with the given value at the specified position in the list. If the position is less than zero, an exception is thrown or the error is handled. If the position is zero, the push_front function is called to add the node to the front of the list. Otherwise, the function iterates through the list until it reaches the node at the specified position, creates a new node, inserts it into the list, and updates the relevant pointers. The new node’s previous pointer is set to the current node, and its next pointer is set to the current node’s next pointer. If the current node’s next pointer is not nullptr, its previous pointer is updated to point to the new node. If the current node’s next pointer is nullptr, the new node is the new tail of the list.

See also  Introduction to Linked List

Remove the node at the specified position in the list

// Remove the node at the specified position in the list
void remove(int pos) {
    if (pos < 0) {
        // Throw an exception or handle the error
    } else if (pos == 0) {
        pop_front();
    } else {
        auto curr = head;
        int i = 0;
        while (curr != nullptr && i < pos - 1) {
            curr = curr->next;
            i++;
        }
        if (curr != nullptr && curr->next != nullptr) {
            auto to_remove = curr->next;
            curr->next = to_remove->next;
            if (to_remove->next != nullptr) {
                to_remove->next->prev = curr;
            } else {
                tail = curr;
            }
            // Decrement the reference count of the node being removed
            to_remove.reset();
        } else {
            // Throw an exception or handle the error
        }
    }
}

The remove function removes the node at the specified position in the list. If the position is less than zero or greater than or equal to the length of the list, an exception is thrown or the error is handled. If the position is zero, the pop_front function is called to remove the node from the front of the list. Otherwise, the function iterates through the list until it reaches the node before the one to remove, updates the relevant pointers, and decrements the reference count of the node being removed to allow it to be garbage-collected.

Get the value of the node at the specified position in the list

// Get the value of the node at the specified position in the list
int get(int pos) {
    if (pos < 0) {
        // Throw an exception or handle theerror    } else {
        auto curr = head;
        int i = 0;
        while (curr != nullptr && i < pos) {
            curr = curr->next;
            i++;
        }
        if (curr != nullptr) {
            return curr->value;
        } else {
        // Throw an exception or handle the error
        }
    }
}

The `get` function returns the value of the node at the specified position in the list. If the position is less than zero or greater than or equal to the length of the list, an exception is thrown or the error is handled. Otherwise, the function iterates through the list until it reaches the node at the specified position and returns its value.

Reverse the order of the nodes in the list

// Reverse the order of the nodes in the list
void reverse() {
    auto curr = head;
    head = tail;
    tail = curr;
    while (curr != nullptr) {
        auto temp = curr->prev;
        curr->prev = curr->next;
        curr->next = temp;
        curr = curr->prev;
    }
}

The `reverse` function reverses the order of the nodes in the list. It swaps the `head` and `tail` pointers, then iterates through the list, swapping the previous and next pointers of each node and updating the `curr` pointer to point to the previous node. This effectively reverses the order of the list.

See also  Java LinkedList Class Implementation Guide and Examples

Add a node to the front of the list

// Add a node to the front of the list
void push_front(int value) {
    auto new_node = make_shared<Node>();
    new_node->value = value;
    new_node->next = head;
    if (head != nullptr) {
        head->prev = new_node;
    }
    head = new_node;
    if (tail == nullptr) {
        tail = head;
    }
}

The push_front function adds a new node with the given value to the front of the list. It creates a new shared pointer to a new node using the make_shared function, sets the node’s value and next pointer to the current head of the list, and updates the head pointer to point to the new node. If the list was empty before this operation, the tail pointer is also updated to point to the new node.

Add a node to the end of the list

// Add a node to the end of the list
void push_back(int value) {
    auto new_node = make_shared<Node>();
    new_node->value = value;
    new_node->prev = tail;
    if (tail != nullptr) {
        tail->next = new_node;
    }
    tail = new_node;
    if (head == nullptr) {
        head = tail;
    }
}

The push_back function adds a new node with the given value to the end of the list. It creates a new shared pointer to a new node using the make_shared function, sets the node’s value and previous pointer to the current tail of the list, and updates the tail pointer to point to the new node. If the list was empty before this operation, the head pointer is also updated to point to the new node.

Remove the first node in the list

// Remove the first node in the list
void pop_front() {
    if (head != nullptr) {
        auto old_head = head;
        head = head->next;
        if (head != nullptr) {
            head->prev = nullptr;
        } else {
            tail = nullptr;
        }
        // Decrement the reference count of the old head node
        old_head.reset();
    }
}

The pop_front function removes the first node in the list. It updates the head pointer to point to the next node in the list, updates the previous pointer of the new head node to nullptr, and decrements the reference count of the old head node to allow it to be garbage-collected.

Remove the last node in the list

// Remove the last node in the list
void pop_back() {
    if (tail != nullptr) {
        auto old_tail = tail;
        tail = tail->prev;
        if (tail != nullptr) {
            tail->next = nullptr;
        } else {
            head = nullptr;
        }
        // Decrement the reference count of the old tail node
        old_tail.reset();
    }
}

The pop_back function removes the last node in the list. It updates the tail pointer to point to the previous node in the list, updates the next pointer of the new tail node to nullptr, and decrements the reference count of the old tail node to allow it to be garbage-collected.

Written by

With 10+ years in software engineering, I specialize in blogging and web development. My skills span front-end, back-end, database design, web security, and SEO. Passionate about crafting helpful digital experiences.