设为首页 加入收藏

TOP

5.6 降低判定树的高度(1)
2013-10-07 14:29:55 来源: 作者: 【 】 浏览:61
Tags:5.6 降低 判定 高度

5.6 降低判定树的高度(1)

5.5节讲述了对非线性索引表的优化,讨论了最大case值和最小case值之差在255以内的情况。当最大case值与最小case值之差大于255,超出索引1字节的表达范围时,上述优化方案同样会造成空间的浪费,此时采用另一种优化方案—判定树:将每个case值作为一个节点,从这些节点中找到一个中间值作为根节点,以此形成一棵二叉平衡树,以每个节点为判定值,大于和小于关系分别对应左子树和右子树,这样可以提高效率。

如果打开O1选项—体积优先,由于有序线性优化和索引表优化都需要消耗额外的空间,因此在体积优先的情况下,这两种优化方案是不被允许的。编译器尽量以二叉判定树的方式来降低程序占用的体积,如代码清单5-17所示。

代码清单5-17 switch树的C++(www.cppentry.com)源码

  1. int nIndex = 0;  
  2.         scanf("%d", &nIndex);  
  3.         switch(nIndex){  
  4.         case 2: printf("nIndex == 2\n");        break;  
  5.         case 3: printf("nIndex == 3\n");        break;  
  6.         case 8: printf("nIndex == 8\n");        break;  
  7.         case 10: printf("nIndex == 10\n");      break;  
  8.         case 35: printf("nIndex == 35\n");      break;  
  9.         case 37: printf("nIndex == 37\n");      break;  
  10.         case 666: printf("nIndex == 666\n");        break;  
  11.         default: printf("default\n");           break;  
  12.     } 

如果代码清单5-17中没有case 666这句代码,可以采用非线性索引表方式进行优化。有了case 666这句代码后,便无法使用仿造if else优化、有序线性优化、非线性索引表优化等方式。需要使用更强大的解决方案,将switch做成树,Debug版代码见代码清单5-18。

代码清单5-18 树结构switch片段—Debug版

  1. switch(nIndex){         // 源码对比  
  2. 00401490    mov     ecx,dword ptr [ebp-4]  
  3. 00401493    mov     dword ptr [ebp-8],ecx  
  4. ; 取出变量nIndex进行比较  
  5. 00401496    cmp     dword ptr [ebp-8],0Ah  
  6. ; 条件跳转,大于10跳转到地址0x004014B9处  
  7. 0040149A    jg      SwitchTree+59h (004014b9)  
  8. 0040149C    cmp     dword ptr [ebp-8],0Ah  
  9. ; 条件跳转,等于10跳转到地址0x004014FD处  
  10. 004014A0    je      SwitchTree+9Dh (004014fd)  
  11. 004014A2    cmp     dword ptr [ebp-8],2  
  12. ; 条件跳转,等于2跳转到地址0x004014D0处  
  13. 004014A6    je          SwitchTree+70h (004014d0)  
  14. 004014A8    cmp     dword ptr [ebp-8],3  
  15. ; 条件跳转,等于3跳转到地址0x004014DF处  
  16. 004014AC   je       SwitchTree+7Fh (004014df)  
  17. 004014AE   cmp  dword ptr [ebp-8],8  
  18. ; 条件跳转,等于8跳转到地址0x004014EE处  
  19. 004014B2    je      SwitchTree+8Eh (004014ee)  
  20. ; JE跳转失败,直接跳转到地址0x00401539(default块首地址)处  
  21. 004014B4    jmp     SwitchTree+0D9h (00401539)  
  22. 004014B9    cmp     dword ptr [ebp-8],23h  
  23. ; 条件跳转,等于35跳转到地址0x0040150C处  
  24. 004014BD    je      SwitchTree+0ACh (0040150c)  
  25. 004014BF    cmp     dword ptr [ebp-8],25h  
  26. ; 条件跳转,等于37跳转到地址0x0040151B处  
  27. 004014C3    je      SwitchTree+0BBh (0040151b)  
  28. 004014C5    cmp     dword ptr [ebp-8],29Ah  
  29. ; 条件跳转,等于666跳转到地址0x0040152A处  
  30. 004014CC    je      SwitchTree+0CAh (0040152a)  
  31. ; JE跳转失败,直接跳转到地址0x00401539(default块首地址)处  
  32. 004014CE    jmp     SwitchTree+0D9h (00401539)  
  33.  
  34. ……      // case 语句块部分略  
  35.  
  36. // default 语句块  
  37. default:printf("default\n");break;      // 源码对比  
  38. 00401539    push    offset string "default\n" (004230b0)  
  39. 0040153E    call    printf (004015e0)  
  40. 00401543    add     esp,4 

分析代码清单5-18得出,在switch的处理代码中,比较判断的次数非常之多。首先与10进行了比较,大于10跳转到地址0x004014B9处,这个地址对应的代码又是条件跳转操作,比较的数值为35。如果不等于35,则与37比较;不等于37又再次与666进行比较;与666比较失败后会跳转到switch结尾或default块的首地址处。到此为止,大于10的比较就全部结束了。从这几处比较可以发现,这类似一个if 分支结构。

继续分析,第一次与10进行比较,小于10则顺序向下执行。再次与2进行比较,如果不等于2,就继续与3比较;如果不等于3,再继续与8进行比较。小于10的比较操作到此就都结束了,很明显,条件跳转指令后,没有语句块,这是一个仿造if else的switch分支结构。大于10的比较情况与小于10的类似,也是一个仿造的if else分支结构。如果每一次比较都以失败告终,最后将只能够执行JMP指令,跳转到地址0x00401539处,即default块首地址。将这两段比较组合后的结构图如图5-9所示。

 
图5-9 二叉判定树
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇5.6 降低判定树的高度(2) 下一篇5.8 编译器对循环结构的优化(2)

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: