c++ leetcode 24题两两交换链表节点8行代码非递归感受一下代码支配的恐怖吧!
前言
做完了题,昨天晚上看了一下国际站,
这人就是覃超老师说的光头哥(其实人家是有头发的),覃超老师对他的评价是"这人经常玩代码艺术",一看标题的话可能觉得他用的是递归,这个题的话一般循环都在20行开外,点开一看,不看不知道一看吓一跳啊,链接: https://leetcode.com/problems/swap-nodes-in-pairs/discuss/11019/7-8-lines-C%2B%2B-Python-Ruby
这是题目的链接:
https://leetcode-cn.com/problems/swap-nodes-in-pairs/submissions/
我昨天也发过这道题的代码的解法:
https://blog.csdn.net/qq_45569601/article/details/107750205
代码如下:
ListNode* swapPairs(ListNode* head) {
ListNode** pp = &head,*a,* b;
while ((a = *pp) && (b = a -> next)) {
a -> next = b -> next;
b -> next = a;
*pp = b;
pp = &(a -> next);
}
return head;
}
简洁漂亮,虽然代码的时间复杂度还是O(N);但是能把代码简洁这种程度,真是个高手.
个人简述代码:
第一行:
ListNode** pp = &head,*a,* b;
pp 是一个二级指针,指向指针的地址,首先pp 指向 指向头结点指针的地址;使用二级指针是一种非常老练的做法,虽然大多数人都知道二级指针,但实际用起来,可没有那么简单
第二行:
while ((a = *pp) && (b = a -> next))
第二行就更牛批了,while循环的判断语句a = *pp 就是 a = head; pp 里面存放的是head 指针的地址, *解引出head 指针指向的地址,a 指针就指向了head 指针指向的地址,如果a为空,他就不执行&&后面的那条语句b = a ->next ; 它与||都具有断路特性,&& 是第一个条件不成立,它就不会执行后面的条件,||是如果第一个条件成立,它也不会执行后面的条件,起到了防御型编程的作用,执行完后判断语句后a 也就是第一个结点,b 是第二个节点
第三行和第四行:
a -> next = b -> next;
b -> next = a;
第三行和第四行经常刷链表题的朋友,不陌生吧? 就是我习惯用的是
ListNode* temp = b -> next;
b -> next = a;
a -> next = temp;
我以前也是没有去哪里想,脑子太笨,真学到了,a -> next = b -> next ; 第一个节点的next指向第三个节点,b -> next =a 第二个节点 的next 指向 第一个节点;
第五行:
*pp = b;
第五行也是最难理解的一行,虽然这只是一个简单的赋值语句, pp(二级指针) 是指向 第一个节点的指针的地址,这个一级指针地址没有变,变得是它这个一级指针指向的地址变成了第二个节点的地址,与最后一行return语句一块解释,
return head;
它的确返回的是head指针,但是它head指针指向的地址已经不是第一个节点的地址了,而是第二个节点的地址,第三四五行做的事情就是 a -> b -> (b -> next) 到 b -> a -> (b-> next) 第三四行已经做到了,但是head 指针指向的a 节点的地址,第五行,要改变的就是head 指针指向的地址
第六行:
pp = &(a -> next);
循环中最后一条语句,pp 指向了指向第三个节点的指针的地址,pp 二级指针指向一级指针的地址改变了,下一次循环的a 指针也就变成了指向第三个节点的地址;依次类推;直到a指针指向的节点地址的next为空循环结束;
总结
如果理解的和我不一样可以探讨一下,如果有不理解的我会在以我的理解再探讨,我把我唯一一张推荐票,给了这篇博客,光头哥绝非凡人,第一眼看到的时候,真就惊呆了,这就是代码的艺术啊.