看动画,拿 Offer:大厂算法面试真题全解析( 三 )


头插法在处理某个结点的指针修改时 , 与直接逆置法一样 , 以处理第 3 个结点为例 , 此时 head 指向的链表为 3、4、5 , temp 结点后的链表为 2、1 。
首先通过代码 next = head->next 备份 head 指针的下一个节点 , 即将 4 号结点的地址存储在 next 指针中 。
然后修改 head 指向结点的 next 指针, 通过代码 head->next = temp.next 使其指向临时头结点的下一个结点 。即将 3 号结点指向 temp 结点后的 2 号结点 。
完成 head 的 next 指针修改后 , 通过代码 temp.next = head;修改临时头结点 temp 的 next 指针, 使 temp 指向 head 指向的结点 。这样就把 3 号结点插入到临时头结点的后面了 。
最后移动 head 指针 , 通过代码 head = next;使 head 指向 next 备份的地址 , 即原链表的 4 号结点 。这样就完成了头插法逆置 3 号节点 。
来看头插法的实现代码 ,  函数 , 传入 head 指针 , 指向待逆置链表 。
首先设置临时头结点 temp , 通过 while 循环逆置链表 , 在循环内部 , 代码 next = head->next , 备份 head 指针的下一个结点;代码 head->next = temp.next , 修改 head 指向的节点 , 使其指向临时头结点 temp 的下一个结点 。
代码 temp.next = head , 使临时头结点 temp 指向 head 指向的结点 。
代码 head = next , 移动 head 指针 , 将其指向 next 备份的地址 。
最终返回临时头结点的下一个节点地址 temp.next , 即逆置后的链表头结点 。
我们来对比一下这两种方法 , 两种方法的不同点是思考角度不同 , 逆置法通过指针的操作进行链表结点的原地逆置 , 头插法通过引入临时头结点将原链表的结点插入至该结点后 。
这两种代码背后含义是相同的 , 具体来说 , 首先设置临时头结点 temp 与逆置指针 ;通过代码 next = head->next;对 head 指针的下一个结点地址备份 。
然后修改 head 指向节点的 next 域 , 使其指向新链表的第一个结点 , 代码分别是 head->next =与 head->next = temp.next , 这里要注意 , 我们并没有使用到 temp 节点的 val 域 , 而与 temp.next 都只是存储新链表第一个结点地址的指针 。
完成修改后 , 移动存储新链表第一个结点的指针 ,  与 temp.next , 将它指向 head;最后 , 将 head 赋值为 next 指向的结点地址 , 继续处理下一个结点 。以上就是逆置法与头插法的相同点与不同点 。
最后我们开发一个 main 函数测试一下程序接口 , 程序设置 a、b、c、d、e 五个节点 , 通过 next 指针将它们连接 。调用将链表进行逆置 , 并通过函数打印逆置前后的链表 。最后提交  , 题目通过测试 。206 链表逆序这道题目就讲完了 。
链表求交点( 160)
今天讲解的题目选自160 链表求交点
题目
已知两个链表 , 指针 headA 指向链表 A 的头节点 , headB 指向链表 B 的头节点 。如果这两个链表相交 , 找到两个链表相交的节点 , 返回该节点地址 。
例如 , 链表 A 和链表 B 相交于 C 结点 , 我们返回 C 节点的地址 。如果两个链表之间没有交点 , 程序返回 null 。
我们要注意 , 求解交点的过程中 , 链表需要保持原有的数据和结构 , 即不能删除节点 , 添加节点或是改变节点内的数据 。