链表

链表是线性数据结构,其中元素存储在节点中,每个节点包含数据和指向下一个节点的指针/引用。与数组不同,链表元素不存储在连续的内存位置中。

链表提供动态内存分配和高效的插入/删除操作,使其非常适用于数据大小未知或频繁变化的应用程序。

单向链表

单向链表是最简单的类型,其中每个节点都指向序列中的下一个节点:

单向链表实现

#include <iostream>
using namespace std;

// Node structure
struct Node {
    int data;
    Node* next;
    
    Node(int value) : data(value), next(nullptr) {}
};

class LinkedList {
private:
    Node* head;

public:
    LinkedList() : head(nullptr) {}
    
    // Insert at beginning
    void insertAtBeginning(int value) {
        Node* newNode = new Node(value);
        newNode->next = head;
        head = newNode;
    }
    
    // Insert at end
    void insertAtEnd(int value) {
        Node* newNode = new Node(value);
        if (head == nullptr) {
            head = newNode;
            return;
        }
        
        Node* temp = head;
        while (temp->next != nullptr) {
            temp = temp->next;
        }
        temp->next = newNode;
    }
    
    // Delete by value
    void deleteValue(int value) {
        if (head == nullptr) return;
        
        if (head->data == value) {
            Node* temp = head;
            head = head->next;
            delete temp;
            return;
        }
        
        Node* current = head;
        while (current->next != nullptr && current->next->data != value) {
            current = current->next;
        }
        
        if (current->next != nullptr) {
            Node* temp = current->next;
            current->next = current->next->next;
            delete temp;
        }
    }
    
    // Display list
    void display() {
        Node* temp = head;
        while (temp != nullptr) {
            cout << temp->data << " -> ";
            temp = temp->next;
        }
        cout << "NULL" << endl;
    }
    
    // Search for value
    bool search(int value) {
        Node* temp = head;
        while (temp != nullptr) {
            if (temp->data == value) {
                return true;
            }
            temp = temp->next;
        }
        return false;
    }
    
    // Destructor
    ~LinkedList() {
        while (head != nullptr) {
            Node* temp = head;
            head = head->next;
            delete temp;
        }
    }
};

int main() {
    LinkedList list;
    
    // Insert elements
    list.insertAtEnd(10);
    list.insertAtEnd(20);
    list.insertAtEnd(30);
    list.insertAtBeginning(5);
    
    cout << "Linked List: ";
    list.display();
    
    // Search
    cout << "Search 20: " << (list.search(20) ? "Found" : "Not Found") << endl;
    cout << "Search 25: " << (list.search(25) ? "Found" : "Not Found") << endl;
    
    // Delete
    list.deleteValue(20);
    cout << "After deleting 20: ";
    list.display();
    
    return 0;
}

双向链表

双向链表的节点具有指向下一个和上一个节点的指针,允许双向遍历:

双向链表实现

#include <iostream>
using namespace std;

struct DoublyNode {
    int data;
    DoublyNode* next;
    DoublyNode* prev;
    
    DoublyNode(int value) : data(value), next(nullptr), prev(nullptr) {}
};

class DoublyLinkedList {
private:
    DoublyNode* head;
    DoublyNode* tail;

public:
    DoublyLinkedList() : head(nullptr), tail(nullptr) {}
    
    // Insert at beginning
    void insertAtBeginning(int value) {
        DoublyNode* newNode = new DoublyNode(value);
        if (head == nullptr) {
            head = tail = newNode;
        } else {
            newNode->next = head;
            head->prev = newNode;
            head = newNode;
        }
    }
    
    // Insert at end
    void insertAtEnd(int value) {
        DoublyNode* newNode = new DoublyNode(value);
        if (tail == nullptr) {
            head = tail = newNode;
        } else {
            tail->next = newNode;
            newNode->prev = tail;
            tail = newNode;
        }
    }
    
    // Display forward
    void displayForward() {
        DoublyNode* temp = head;
        cout << "Forward: ";
        while (temp != nullptr) {
            cout << temp->data << " <-> ";
            temp = temp->next;
        }
        cout << "NULL" << endl;
    }
    
    // Display backward
    void displayBackward() {
        DoublyNode* temp = tail;
        cout << "Backward: ";
        while (temp != nullptr) {
            cout << temp->data << " <-> ";
            temp = temp->prev;
        }
        cout << "NULL" << endl;
    }
    
    // Delete by value
    void deleteValue(int value) {
        DoublyNode* temp = head;
        while (temp != nullptr && temp->data != value) {
            temp = temp->next;
        }
        
        if (temp == nullptr) return; // Value not found
        
        if (temp->prev) {
            temp->prev->next = temp->next;
        } else {
            head = temp->next;
        }
        
        if (temp->next) {
            temp->next->prev = temp->prev;
        } else {
            tail = temp->prev;
        }
        
        delete temp;
    }
    
    ~DoublyLinkedList() {
        while (head != nullptr) {
            DoublyNode* temp = head;
            head = head->next;
            delete temp;
        }
    }
};

int main() {
    DoublyLinkedList list;
    
    list.insertAtEnd(10);
    list.insertAtEnd(20);
    list.insertAtEnd(30);
    list.insertAtBeginning(5);
    
    list.displayForward();
    list.displayBackward();
    
    list.deleteValue(20);
    cout << "After deleting 20:" << endl;
    list.displayForward();
    
    return 0;
}

优缺点

优点

  • 动态大小 - 可以在运行时增长或收缩
  • 在开头高效插入/删除 - O(1)
  • 内存高效 - 按需分配内存
  • 无内存浪费 - 不像固定大小的数组

缺点

  • 无随机访问 - 必须从头开始遍历
  • 存储指针需要额外内存
  • 对缓存不友好 - 元素在内存中分散
  • 单向链表无法向后遍历