c++中如何实现简单链表_c++单链表创建与遍历【核心】

4次阅读

最直白单链表实现:定义node含val和next(必初始化为nullptr),new节点后立即设next=nullptr,用指针手动串联;遍历时判curr!=nullptr;头插需node*& head,删除前保存next再delete,避免悬空指针

c++中如何实现简单链表_c++单链表创建与遍历【核心】

怎么用 c++ 写一个能跑起来的单链表

别从模板类或智能指针起步,先用最直白的方式把节点连上、遍历出来。核心就三件事:定义节点结构、手动 new 出节点、用指针串起来。

常见错误是 next 指针没初始化,导致遍历时访问野地址;或者插入时忘了更新前驱的 next,链表直接断掉。

  • Struct Node { int val; Node* next; }; —— next 必须显式初始化为 nullptr,否则值随机
  • 创建头节点后,立刻设 head = nullptr;每次 new Node 后,马上写 node->next = nullptr
  • 遍历必须检查 curr != nullptr,不能只写 curr->next != nullptr,否则最后一个节点被跳过

示例片段:

Node* head = nullptr; Node* n1 = new Node{1, nullptr}; Node* n2 = new Node{2, nullptr}; n1->next = n2; head = n1; <p>Node* curr = head; while (curr != nullptr) { std::cout << curr->val << " "; curr = curr->next; }

为什么不用 std::list 而要手写

不是为了造轮子,而是为了理解内存布局和指针操作——比如调试时看到 0xcdcdcdcd0xbaadf00d 这类错误码,就得靠手写链表练出条件反射。

立即学习C++免费学习笔记(深入)”;

std::list 是双向、带哨兵节点、分配器可替换的完整实现,而手写单链表只有 next 一个指针,内存连续性差、缓存不友好,但胜在每个字节都可控。

  • 面试/笔试里考的是 insert_afterdelete_by_value 这类逻辑,std::listerase 不暴露底层指针,没法考察指针操作细节
  • 嵌入式或内核模块里常禁用 STL,new 都可能被替换成自定义池分配,这时候 Node* 才是真实接口
  • 性能上,手写链表的 push_front 是 O(1),但随机访问仍是 O(n),这点不会因为换容器改变

delete 时最容易漏掉的两个点

不是“忘了 delete”,而是删得不干净,留下悬空指针或重复释放。

  • 删除节点前,必须先保存它的 next,再 delete 当前节点,否则 curr->next 就丢了
  • 删完要把原指针(比如 headprev->next)设为 nullptr 或新值,否则它仍指向已释放内存,后续解引用就是未定义行为
  • 遍历中删除时,别在循环条件里写 curr = curr->next,应在循环体内处理指针转移

典型翻车代码:delete curr; curr = curr->next; —— curr->next 此时已不可读。

头插、尾插、按值删,参数怎么传才安全

关键看谁负责改“链表入口”——也就是 head 指针本身。如果函数可能让 head 指向新节点(比如空链表时头插),就必须传 Node*& head,而不是 Node* head

  • 头插:需修改 head,参数用 Node*& head
  • 尾插:若已有 tail 指针可维护,传 Node*& tail;否则只能遍历到末尾,此时 head 不变,传 Node* head 即可
  • 按值删除:要改前驱的 next,所以需要二级指针或引用,如 Node** prev_next,或者干脆传入 Node*& head 并在内部处理头节点特例

传错参数类型,编译可能过,但运行时 head 始终不变,你会以为逻辑错了,其实是调用方式错了。

链表看着简单,但每个 ->next 和每处 delete 都得对得上号;少一个 nullptr 初始化,多一次 curr = curr->next 的位置错,就卡半天。

text=ZqhQzanResources