手把手教你理解单向链表:代码注释+新手入门指南
一、简介和应用
单向链表是一种基础的数据结构,它由一系列节点组成,每个节点包含数据和指向下一个节点的指针。这种结构在数据存储和动态操作中非常实用,例如实现队列、栈,或在需要频繁插入、删除的场景中(如用户登录记录、任务列表等)。相比数组,链表无需连续内存空间,插入和删除效率更高,但无法随机访问元素。
二、特点和注意事项
特点:
1. 灵活性:节点动态分配,支持任意长度。
2. 简单性:单向指针,逻辑清晰,适合新手入门。
3. 操作高效:插入和删除节点只需修改指针,时间复杂度为O(1)(找到位置后)。
注意事项:
1.避免空指针操作:访问节点前需判断是否为nullptr。
2.内存管理:手动分配节点(如new node)后,需确保程序结束前释放(未实现删除功能时需注意)。
3.索引越界:插入、删除等操作需检查索引是否合法。
三、代码的实现步骤
1. 定义节点结构:包含数据data和指向下一个节点的指针next。
2. 创建链表类:linklist类以head指针指向链表头部。
3. 添加节点:从头部遍历到末尾,将新节点插入末尾。
4. 插入节点:根据索引找到目标位置的前一个节点,插入新节点并调整指针。
5. 删除节点:找到目标位置前一个节点,跳过要删除的节点并连接后续节点。
6. 修改和查询:通过索引遍历到目标节点,修改数据或返回数据。
7. 反转链表:提供递归和非递归两种方法,改变指针方向形成逆序链表。
四、代码与注释
#include <iostream> using namespace std; // 定义节点结构 struct node { int data = 0; // 节点存储的数据(默认值0) node* next = nullptr; // 指向下一个节点的指针 }; class linklist { public: node* head = new node; // 链表头部节点(初始化为空节点) // 1. 添加节点到末尾 void add(int data) { node* tmp = head; // 临时指针从头部开始遍历 while (tmp->next!= nullptr) { // 循环直到末尾 tmp = tmp->next; } node* datanode = new node; // 创建新节点 datanode->data = data; // 赋值数据 tmp->next = datanode; // 将末尾指针指向新节点 } // 2. 在指定索引插入节点 void insert(int data, int idx) { node* datanode = new node; // 创建新节点 datanode->data = data; node* tmp = head; // 临时指针从头部开始 for (int i = 0; i < idx; i++) { // 循环到索引位置的前一个节点 tmp = tmp->next; } datanode->next = tmp->next; // 新节点指向原索引位置的节点 tmp->next = datanode; // 前一个节点指向新节点 } // 3. 删除指定索引的节点 void deleteNode(int idx) { node* tmp = head; for (int i = 0; i < idx; i++) { tmp = tmp->next; } tmp->next = tmp->next->next; // 跳过要删除的节点,连接后续节点 } // 4. 修改指定索引节点的数据 void change(int data, int idx) { node* tmp = head; for (int i = 0; i <= idx; i++) { // 注意:i <= idx,因为要访问到目标节点 tmp = tmp->next; } tmp->data = data; } // 5. 查询指定索引的节点数据 int select(int idx) { node* tmp = head; for (int i = 0; i <= idx; i++) { tmp = tmp->next; } return tmp->data; // 返回目标节点的数据 } // 6. 反转链表(递归方法) node* reverse(node* head) { if (head == nullptr || head->next == nullptr) { // 递归终止条件:空链表或只有一个节点 return head; } node* newHead = reverse(head->next); // 递归处理后续节点 head->next->next = head; // 原头部的下一个节点指向原头部 head->next = nullptr; // 原头部指向空(新链表的末尾) linklist::head->next = newHead; // 更新链表头部指针(注意:此处可能影响原链表结构,需谨慎使用) return newHead; } // 7. 反转链表(迭代方法) node* otherReverse(node* head) { node* a = head; // 当前节点 node* b = a->next; // 下一个节点 a->next = nullptr; // 初始化反转后的头部 while (b) { // 迭代反转 node* tmp = b->next; // 暂存下一个节点 b->next = a; // 反转指针方向 a = b; // 更新当前节点 b = tmp; // 更新下一个节点 } linklist::head->next = a; // 更新链表头部指针 return a; } };
五、总结
单向链表是数据结构的入门基石,掌握其原理和操作能帮助你理解更复杂的链表(如双向链表、循环链表)。本文通过代码注释和步骤拆解,带你从零开始构建链表,并实现基本操作及反转。建议新手多动手实践,尝试修改代码(如添加删除节点的内存释放功能),逐步加深理解。记住:指针操作需谨慎,逻辑清晰是关键!
原创内容 转载请注明出处