1.介绍
链表是C++中常用的一种动态数据结构,它有一系列节点组成,每个节点包含数据和指向下一个节点的指针。链表与数组不同,它的内存分配是动态的,不需要连续的内存空间。
2.链表的基本概念
(1)节点(Node):每个节点包含两部分:
数据域:存储数据
指针域:指向下一个节点的地址。
在C++中,节点通常用结构体或类表示。
(2)链表的类型:
单向链表:每个节点只有一个指针,指向下一个节点。
双向链表:每个节点有两个指针,分别指向前一个节点和后一个节点。
循环链表:尾节点的指针指向头节点,形成一个环。
(3)链表的优点
动态分配内存,不需要预先知道数据的大小。
插入和删除操作效率高(时间复杂度为O(1),前提是已知插入/删除位置)。
(4)链表的缺点:
访问元素需要从头节点开始遍历,时间复杂度为O(n)。
需要额外的内存空间存储指针。
3.链表的具体实现
(1)单向链表的实现以及各种操作。
#include <iostream>
// 定义链表节点
struct Node {
int data; // 数据域
Node* next; // 指针域,指向下一个节点
// 构造函数
Node(int val) : data(val), next(nullptr) {}
};
// 定义链表类
class LinkedList {
private:
Node* head; // 头节点指针
public:
// 构造函数
LinkedList() : head(nullptr) {}
// 析构函数,释放链表内存
~LinkedList() {
Node* current = head;
while (current != nullptr) {
Node* next = current->next;
delete current;
current = next;
}
}
// 在链表头部插入节点
void insertAtHead(int val) {
Node* newNode = new Node(val);
newNode->next = head;
head = newNode;
}
// 在链表尾部插入节点
void insertAtTail(int val) {
Node* newNode = new Node(val);
if (head == nullptr) {
head = newNode;
return;
}
Node* current = head;
while (current->next != nullptr) {
current = current->next;
}
current->next = newNode;
}
// 删除链表中指定值的节点
void deleteNode(int val) {
if (head == nullptr) return;
// 如果要删除的是头节点
if (head->data == val) {
Node* temp = head;
head = head->next;
delete temp;
return;
}
// 查找要删除的节点
Node* current = head;
while (current->next != nullptr && current->next->data != val) {
current = current->next;
}
// 如果找到要删除的节点
if (current->next != nullptr) {
Node* temp = current->next;
current->next = current->next->next;
delete temp;
}
}
// 打印链表
void printList() const {
Node* current = head;
while (current != nullptr) {
std::cout << current->data << " -> ";
current = current->next;
}
std::cout << "nullptr" << std::endl;
}
};
(2)双向链表的实现
双向链表每个节点有两个指针,分别是前指针与后指针。
#include <iostream>
// 定义双向链表节点
struct Node {
int data;
Node* prev;
Node* next;
// 构造函数
Node(int val) : data(val), prev(nullptr), next(nullptr) {}
};
// 定义双向链表类
class DoublyLinkedList {
private:
Node* head; // 头节点指针
public:
// 构造函数
DoublyLinkedList() : head(nullptr) {}
// 析构函数,释放链表内存
~DoublyLinkedList() {
Node* current = head;
while (current != nullptr) {
Node* next = current->next;
delete current;
current = next;
}
}
// 在链表尾部插入节点
void insertAtTail(int val) {
Node* newNode = new Node(val);
if (head == nullptr) {
head = newNode;
return;
}
Node* current = head;
while (current->next != nullptr) {
current = current->next;
}
current->next = newNode;
newNode->prev = current;
}
// 打印链表
void printList() const {
Node* current = head;
while (current != nullptr) {
std::cout << current->data << " <-> ";
current = current->next;
}
std::cout << "nullptr" << std::endl;
}
};
4.链表的应用场景
动态数据存储:当数据量不确定时,链表可以动态分配内存。
频繁插入和删除:链表在已知位置插入和删除效率高。
实现其他数据结构:如栈、队列、哈希表等。
5.总结
链表是一种灵活的数据结构,适合动态数据存储和频繁插入/删除的操作。
单向链表简单易于实现,双向链表支持双向遍历。
链表的缺点是访问元素效率较低,需要额外的内存存储指针。
通过链表,可以更好地理解指针和动态内存管理的概念。
如有错误,敬请指正!!!