从objdump汇编分析三元运算的使用

公众号:
在这里插入图片描述
在做一个难度标记为简单的力扣题时,本以为轻松能过,却遇到一点小问题,一时竟没能想到原因。
借助objdump分析汇编后,才恍然大悟。

汇编指令:

MOV     传送字或字节
CMP     比较.(两操作数作减法,仅修改标志位,不回送结果)
JLE     小于或等于转移
CALLQ   过程调用
ADD     加

题目

力扣题库:https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/
104. 二叉树的最大深度
给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

示例:
给定二叉树 [3,9,20,null,null,15,7],
在这里插入图片描述
返回它的最大深度 3 。

解题思想:遍历寻找最深

代码1:

class Solution {
public:
    #define MAX_INT(x, y) ((x)>(y) ? (x) : (y)) /*获取Max*/
    
    int maxDepth(TreeNode* root) {
        if(NULL == root) {
            return 0;
        }
        
        return MAX_INT(maxDepth(root->left), maxDepth(root->right)) + 1; /*向子树查找最大深度*/
    }
};

运行结果:

在这里插入图片描述
一时没感觉哪里不正常,为何超时了呢

代码改为如下:
代码2:

class Solution {
public:
    #define MAX_INT(x, y) ((x)>(y) ? (x) : (y))
    
    int maxDepth(TreeNode* root) {
        if(NULL == root) {
            return 0;
        }
        
        int iLeft = maxDepth(root->left);/*左子树*/
        int iRight = maxDepth(root->right);/*右子树*/
        return MAX_INT(iLeft, iRight) + 1;
    }
};

运行结果:
在这里插入图片描述

比较汇编

一时竟没想到原因,上objdump。
使用objdump -dlS 命令,输出汇编信息

-d:将代码段反汇编
-S:将代码段反汇编的同时,将反汇编代码和源代码交替显示,编译时需要给出-g,即需要调试信息。
-l:反汇编代码中插入源代码的文件名和行号。

编译源码时,添加-g参数

g++  treetest.cpp  -o treetest -g                         
objdump -dlS treetest > treetest.asm

代码1的汇编:

return MAX_INT(maxDepth(root->left), maxDepth(root->right)) + 1;
  400779:	48 8b 45 e0          	mov    -0x20(%rbp),%rax
  40077d:	48 8b 50 08          	mov    0x8(%rax),%rdx
  400781:	48 8b 45 e8          	mov    -0x18(%rbp),%rax
  400785:	48 89 d6             	mov    %rdx,%rsi
  400788:	48 89 c7             	mov    %rax,%rdi
  40078b:	e8 ca ff ff ff       	callq  40075a <_ZN8Solution8maxDepthEP8TreeNode>
  400790:	89 c3                	mov    %eax,%ebx
  400792:	48 8b 45 e0          	mov    -0x20(%rbp),%rax
  400796:	48 8b 50 10          	mov    0x10(%rax),%rdx
  40079a:	48 8b 45 e8          	mov    -0x18(%rbp),%rax
  40079e:	48 89 d6             	mov    %rdx,%rsi
  4007a1:	48 89 c7             	mov    %rax,%rdi
  4007a4:	e8 b1 ff ff ff       	callq  40075a <_ZN8Solution8maxDepthEP8TreeNode>
  4007a9:	39 c3                	cmp    %eax,%ebx
  4007ab:	7e 1c                	jle    4007c9 <_ZN8Solution8maxDepthEP8TreeNode+0x6f>
/home/wangzhaohui/treetest/treetest2.cpp:14 (discriminator 1)
  4007ad:	48 8b 45 e0          	mov    -0x20(%rbp),%rax
  4007b1:	48 8b 50 08          	mov    0x8(%rax),%rdx
  4007b5:	48 8b 45 e8          	mov    -0x18(%rbp),%rax
  4007b9:	48 89 d6             	mov    %rdx,%rsi
  4007bc:	48 89 c7             	mov    %rax,%rdi
  4007bf:	e8 96 ff ff ff       	callq  40075a <_ZN8Solution8maxDepthEP8TreeNode>
  4007c4:	83 c0 01             	add    $0x1,%eax
  4007c7:	eb 1a                	jmp    4007e3 <_ZN8Solution8maxDepthEP8TreeNode+0x89>
/home/wangzhaohui/treetest/treetest2.cpp:14 (discriminator 2)
  4007c9:	48 8b 45 e0          	mov    -0x20(%rbp),%rax
  4007cd:	48 8b 50 10          	mov    0x10(%rax),%rdx
  4007d1:	48 8b 45 e8          	mov    -0x18(%rbp),%rax
  4007d5:	48 89 d6             	mov    %rdx,%rsi
  4007d8:	48 89 c7             	mov    %rax,%rdi
  4007db:	e8 7a ff ff ff       	callq  40075a <_ZN8Solution8maxDepthEP8TreeNode>
  4007e0:	83 c0 01             	add    $0x1,%eax

代码2的汇编:

        int iLeft = maxDepth(root->left);
  400778:	48 8b 45 e0          	mov    -0x20(%rbp),%rax
  40077c:	48 8b 50 08          	mov    0x8(%rax),%rdx
  400780:	48 8b 45 e8          	mov    -0x18(%rbp),%rax
  400784:	48 89 d6             	mov    %rdx,%rsi
  400787:	48 89 c7             	mov    %rax,%rdi
  40078a:	e8 cb ff ff ff       	callq  40075a <_ZN8Solution8maxDepthEP8TreeNode>
  40078f:	89 45 fc             	mov    %eax,-0x4(%rbp)
/home/wangzhaohui/treetest/treetest.cpp:17
        int iRight = maxDepth(root->right);
  400792:	48 8b 45 e0          	mov    -0x20(%rbp),%rax
  400796:	48 8b 50 10          	mov    0x10(%rax),%rdx
  40079a:	48 8b 45 e8          	mov    -0x18(%rbp),%rax
  40079e:	48 89 d6             	mov    %rdx,%rsi
  4007a1:	48 89 c7             	mov    %rax,%rdi
  4007a4:	e8 b1 ff ff ff       	callq  40075a <_ZN8Solution8maxDepthEP8TreeNode>
  4007a9:	89 45 f8             	mov    %eax,-0x8(%rbp)
/home/wangzhaohui/treetest/treetest.cpp:19
        
        return MAX_INT(iLeft, iRight) + 1;
  4007ac:	8b 45 fc             	mov    -0x4(%rbp),%eax
  4007af:	3b 45 f8             	cmp    -0x8(%rbp),%eax
  4007b2:	7e 08                	jle    4007bc <_ZN8Solution8maxDepthEP8TreeNode+0x62>
/home/wangzhaohui/treetest/treetest.cpp:19 (discriminator 1)
  4007b4:	8b 45 fc             	mov    -0x4(%rbp),%eax
  4007b7:	83 c0 01             	add    $0x1,%eax
  4007ba:	eb 06                	jmp    4007c2 <_ZN8Solution8maxDepthEP8TreeNode+0x68>
/home/wangzhaohui/treetest/treetest.cpp:19 (discriminator 2)
  4007bc:	8b 45 f8             	mov    -0x8(%rbp),%eax
  4007bf:	83 c0 01             	add    $0x1,%eax

对比一下汇编结果,可以顿时理解错在哪里了,错在对三元运算符的使用上了。
从代码1的汇编结果来看,可以看到有4次过程调用callq指令,callq调用的就是class Solution中的函数maxDepth。而代码2中,仅有两次callq指令。
这简单道理我竟然还用上了objdump去看汇编,预处理一下,就能明显看到问题。

预处理

g++   -E   treetest.cpp

得到对三元运算符的预处理

int maxDepth(TreeNode* root) {
    if(__null == root)
    {
        return 0;
    }

    return ((maxDepth(root->left))>(maxDepth(root->right)) ? (maxDepth(root->left)) : (maxDepth(root->right))) + 1;
}

可以看出,代码1中错误的使用了三元运算符,虽然能算出最终结果,行数少了,省了定义两个变量,但是return动作中,都要调用两次maxDepth,原本时间复杂度是O(n),现在成了O(2n)。
要吸取教训。。。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值