遍歷二叉樹的九種算法

  好久未更新博客了,翻出之前的一個算法集,作了些修改,發到這裏,以饗讀者。javascript

  算法是關於二叉樹遍歷的內容。二叉樹遍歷傳統上通常有四種算法:一、遞歸前序遍歷,二、遞歸中序遍歷,三、遞歸後序遍歷,4、非遞歸層次遍歷(隊列輔助)。這四種算法都是大學教課書《數據結構》上的內容,前三種都很是簡單,最後一種略略複雜一點兒,這裏就不贅述了,只給出javascript的源程序。css

  另外五種分別是:一、非遞歸前序遍歷(單棧輔助),二、非遞歸中序遍歷(單棧輔助),三、非遞歸後序遍歷(單棧輔助),四、非遞歸後序遍歷(雙棧輔助),五、遞歸層次遍歷。這五種算法中算法三、4不容易理解,可在Visual Studio中單步執行,並跟蹤棧的狀態。而算法5則很是精巧,層次遍歷通常多選用隊列輔助的算法,算法5的時間、空間效率並不比依靠隊列輔助的層次遍歷算法更低,但對學習遞歸思想很是有幫助,故此次翻出舊做時,一併加上了。html

  算法使用javascript編寫,使用了javascript的自定義對象和爲已有對象添加自定義方法的功能。下面是完整的HTML文件(單文件),直接保存後就能夠運行了。 java

  
  
  
  
  1. <html xmlns="http://www.w3.org/1999/xhtml"> 
  2. <head> 
  3. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
  4. <title>Algorithm Of Traversing Binary Tree - 夢遼軟件</title> 
  5. <style type="text/css"> 
  6. P{  
  7.     font-family:宋體;  
  8.     font-size:9pt;  
  9. }  
  10. </style> 
  11. </head> 
  12. <body> 
  13. <p>二叉樹遍歷算法<br /> 
  14. 白宇 - 夢遼軟件工做室 - 博訊網絡有限責任公司<br /> 
  15. 2011.05.27<br /> 
  16. 2013.04.13(增長遞歸層次遍歷)</p> 
  17. <p>二叉樹示意圖:</p> 
  18. <pre>           1  
  19.           / \  
  20.          /   \  
  21.         /     \  
  22.        /       \  
  23.       /         \  
  24.      2           3  
  25.     / \           \  
  26.    /   \           \  
  27.   /     \           \  
  28.  /       \           \  
  29. 4         5           6  
  30.  \       /           / \  
  31.   \     /           /   \  
  32.    7   8           9     10  
  33.   /   /           / \     \  
  34. 11  12          13   14    15</pre> 
  35. <script type="text/javascript"> 
  36. function BTNode(value){ //自定義對象的構造函數  
  37.     this.value=value;  
  38.     this.left=null;  
  39.     this.right=null;  
  40. }  
  41. //爲Array對象添加自定義方法  
  42. Array.prototype.isEmpty=function(){return this.length==0;}; //用數組模擬棧或隊,判空方法  
  43.  
  44. //=============================================================  
  45.  
  46. function show(value){ //顯示二叉樹的節點  
  47.     document.write(value+" ");  
  48. }  
  49. function buildTree(){ //生成一顆如上圖所示的二叉樹  
  50.     var root=new BTNode(1);  
  51.     root.left=new BTNode(2);  
  52.     root.right=new BTNode(3);  
  53.     root.left.left=new BTNode(4);  
  54.     root.left.right=new BTNode(5);  
  55.     root.right.right=new BTNode(6);  
  56.     root.left.left.right=new BTNode(7);  
  57.     root.left.right.left=new BTNode(8);  
  58.     root.right.right.left=new BTNode(9);  
  59.     root.right.right.right=new BTNode(10);  
  60.     root.left.left.right.left=new BTNode(11);  
  61.     root.left.right.left.left=new BTNode(12);  
  62.     root.right.right.left.left=new BTNode(13);  
  63.     root.right.right.left.right=new BTNode(14);  
  64.     root.right.right.right.right=new BTNode(15);  
  65.     return root;  
  66. }  
  67. function preorder(root){ //遞歸前序遍歷  
  68.     if(root==null) return;  
  69.     show(root.value); //顯示根節點  
  70.     preorder(root.left); //前序遍歷左子樹  
  71.     preorder(root.right); //前序遍歷右子樹  
  72. }  
  73. function inorder(root){ //遞歸中序遍歷  
  74.     if(root==null) return;  
  75.     inorder(root.left);  
  76.     show(root.value);  
  77.     inorder(root.right);  
  78. }  
  79. function postorder(root){ //遞歸後序遍歷  
  80.     if(root==null) return;  
  81.     postorder(root.left);  
  82.     postorder(root.right);  
  83.     show(root.value);  
  84. }  
  85. function getDepth(root){ //遞歸層次遍歷 - 獲取二叉樹深度  
  86.     if(root==null) return 0;  
  87.     var leftDepth=getDepth(root.left);  
  88.     var rightDepth=getDepth(root.right);  
  89.     return Math.max(leftDepth, rightDepth)+1; //返回+1表示加當前層  
  90. }  
  91. function showNodeOfLevel(root, level){ //遞歸層次遍歷 - 遍歷某一層節點  
  92.     if(root==null||level<0) return;  
  93.     if(level==0) show(root.value);  
  94.     showNodeOfLevel(root.left, level-1);  
  95.     showNodeOfLevel(root.right, level-1);  
  96. }  
  97. function levelorder(root){ //遞歸層次遍歷  
  98.     var depth=getDepth(root);  
  99.     for(var i=0;i<depth;i++)  
  100.         showNodeOfLevel(root, i)  
  101. }  
  102. function iterativePreorder(root){ //非遞歸前序遍歷  
  103.     var stack=[]; //模擬棧  
  104.     stack.push(root);  
  105.     do{  
  106.         if((root=stack.pop())!=null){ //出棧  
  107.             show(root.value);  
  108.             stack.push(root.right); //右子節點入棧  
  109.             stack.push(root.left); //左子節點入棧  
  110.         }  
  111.     }while(!stack.isEmpty());  
  112. }  
  113. function iterativeInorder(root){ //非遞歸中序遍歷  
  114.     var stack=[];  
  115.     while(true){  
  116.         for(;root!=null;rootroot=root.left) //將當前節點左子樹的所有節點逐一入棧  
  117.             stack.push(root);  
  118.         if(stack.isEmpty()) break;  
  119.         root=stack.pop();  
  120.         show(root.value);  
  121.         rootroot=root.right; //遍歷右子樹  
  122.     }  
  123. }  
  124. function iterativeSingleStackPostorder(root){ //非遞歸後序遍歷(單棧)  
  125.     var stack=[],flag=root; //flag標識已經遍歷過的節點  
  126.     while(root!=null){ //逐一處理每一個節點的左右子樹  
  127.         for(;root.left!=null;rootroot=root.left)  
  128.             stack.push(root); //左子樹的節點逐一入棧  
  129.         while(root.right==null||root.right==flag){ //需判斷上次遍歷的節點是不是當前節點的右節點  
  130.             show(root.value);  
  131.             flag=root;  
  132.             if(stack.isEmpty()) return;  
  133.             root=stack.pop();  
  134.         }  
  135.         stack.push(root); //多是從新將該節點入棧  
  136.         rootroot=root.right; //轉向右子樹  
  137.     }  
  138. }  
  139. function iterativeDoubleStackPostorder(root){ //非遞歸後序遍歷(雙棧)  
  140.     var stack=[],result=[];  
  141.     if(root!=null) stack.push(root);  
  142.     while(!stack.isEmpty()){ //按照根左右順序逐一入棧、出棧、二次入棧  
  143.         result.push(root=stack.pop());  
  144.         if(root.left!=null) stack.push(root.left);  
  145.         if(root.right!=null) stack.push(root.right);  
  146.     }  
  147.     while(!result.isEmpty())  
  148.         show(result.pop().value);  
  149. }  
  150. function iterativeLevelorder(root){ //非遞歸層次遍歷  
  151.     var queue=[]; //模擬隊列  
  152.     queue.unshift(root); //插入根節點到隊列最前面  
  153.     do{  
  154.         if((root=queue.pop())!=null){ //從隊列最後面取節點  
  155.             show(root.value);  
  156.             queue.unshift(root.left); //左子節點入隊  
  157.             queue.unshift(root.right); //右子節點入隊  
  158.         }  
  159.     }while(!queue.isEmpty());  
  160. }  
  161.  
  162. var root=buildTree();  
  163. document.write("<p>遞歸前序遍歷:");  
  164. preorder(root);  
  165. document.write("</p><p>遞歸中序遍歷:");  
  166. inorder(root);  
  167. document.write("</p><p>遞歸後序遍歷:");  
  168. postorder(root);  
  169. document.write("</p><p>遞歸層次遍歷:");  
  170. levelorder(root);  
  171. document.write("</p><p>非遞歸前序遍歷(單棧):");  
  172. iterativePreorder(root);  
  173. document.write("</p><p>非遞歸中序遍歷(單棧):");  
  174. iterativeInorder(root);  
  175. document.write("</p><p>非遞歸後序遍歷(單棧):");  
  176. iterativeSingleStackPostorder(root);  
  177. document.write("</p><p>非遞歸後序遍歷(雙棧):");  
  178. iterativeDoubleStackPostorder(root);  
  179. document.write("</p><p>非遞歸層次遍歷(隊列):");  
  180. iterativeLevelorder(root);  
  181. document.write("</p>");  
  182. </script> 
  183. </body> 
  184. </html> 

運行截圖:算法

相關文章
相關標籤/搜索