程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 二叉樹的12大問題

二叉樹的12大問題

編輯:C++入門知識

二叉樹的常見問題有如下幾個,如果解決好了,就跟鏈表一樣輕松:唯一不一樣的是,二叉樹是非線性結構。常見的問題如下 1.二叉樹三種周游(traversal)方式:   2.怎樣從頂部開始逐層打印二叉樹結點數據   3.如何判斷一棵二叉樹是否是平衡二叉樹   4.設計一個算法,找出二叉樹上任意兩個節點的最近共同父結點,復雜度如果是O(n2)則不得      分。   5.如何不用遞歸實現二叉樹的前序/後序/中序遍歷?   6.在二叉樹中找出和為某一值的所有路徑   7.怎樣編寫一個程序,把一個有序整數數組放到二叉樹中?   8.判斷整數序列是不是二叉搜索樹的後序遍歷結果   9.求二叉樹的鏡像   10.一棵排序二叉樹(即二叉搜索樹BST),令 f=(最大值+最小值)/2,設計一個算法,找出距      離f值最近、大於f值的結點。復雜度如果是O(n2)則不得分。   11.把二叉搜索樹轉變成排序的雙向鏈表   12.打印二叉樹中的所有路徑(與題目5很相似) 解決思路: 1.二叉樹三種周游(traversal)方式:任何一本數據結構的書都有描述,略過; 2.怎樣從頂部開始逐層打印二叉樹結點數據? 設置一個隊列,然後只要隊列不為空,將對首元素的左右孩子加入隊列(如果左右孩子不為空),然後將隊列的首元素出對即可,如下圖所示: 二叉樹如下圖所示:   那麼,整個過程如下:   自然,就輸出了a,b,c,d,e,f   3.如何判斷一個二叉樹是否是平衡的? 太簡單了,利用遞歸就可以了:判斷根節點的左右子樹深度之差是否小於等於1(這裡需要用到求深度的方法),如果是,根節點就是平衡的;然後,在判斷根節點的左孩子和右孩子是否是平衡的。如此繼續下去,直到遇見葉子節點。一旦不是,立刻返回false; 計一個算法,找出二叉樹上任意兩個節點的最近共同父結點,復雜度如果是O(n2)則不得分 首先找到這兩個點key1和key2,並且記錄下找到這兩個點的路徑Path1和Path2。然後,找到第一個點k滿足,key1<k<key2就可以了。 如圖:   假設key1 = 5,key2 = 7,那麼顯然,Path1{8,6,5}, Path2{8,6,7}。滿足第一個key1<k<key2的k為6。故k = 6。 至於怎麼求出Path1和Path2,可以看問題12。 5.如何不用遞歸實現二叉樹的前序/後序/中序遍歷?(網易面試就問到了,悲劇了,當時一下子卡住了) 看看書,基本任何一本數據結構的書都有,主要利用棧。 6.在二叉樹中找出和為某一值的所有路徑? 還是先解決12題目,訪問二叉樹到葉子節點的任意路徑。這個問題解決了,自然求和看是否滿足條件就可以了。 7.怎樣編寫一個程序,把一個有序整數數組放到二叉樹中? 遞歸,還是利用遞歸: 設有int array[begin,end],首先將array[(begin + end)/2]加入二叉樹,然後遞歸去做array[begin,(begin + end)/2 - 1]和array[(begin + end)/2 + 1, end]。注意寫好函數的形式就可以了。一切都很自然。 8.判斷整數序列是不是二叉搜索樹的後序遍歷結果? 看看吧,後續遍歷是這樣做的:左右根,所以訪問的最有一個節點實際上就是整棵二叉樹的根節點root:然後,找到第一個大於該節點值的根節點b,b就是root右子樹最左邊的節點(大於根節點的最小節點)。那麼b前面的就是root的左子樹。既然是二叉搜索樹的遍歷結果,那麼在b和root之間的遍歷結果,都應該大於b。去拿這個作為判斷的條件。 9.求二叉樹的鏡像? 還是利用遞歸:只要節點不為空,交換左右子樹的指針,然後在分別求左子樹的鏡像,再求右子樹的鏡像,直到節點為NULL。 10.一棵排序二叉樹(即二叉搜索樹BST),令 f=(最大值+最小值)/2,設計一個算法,找出距離f值最近、大於f值的結點。復雜度如果是O(n2)則不得分。 首先,在BST中,最小值就是最左邊的節點,最大值就是最右邊的節點。 在分別求出min和max後,求出f。然後利用查找,找出一個大於f的節點就可以了。 復雜度為logN。 11.把二叉搜索樹轉變成排序的雙向鏈表 12..打印二叉樹中的所有路徑 路徑的定義就是從根節點到葉子節點的點的集合。 還是利用遞歸:用一個list來保存經過的節點,如果已經是葉子節點了,那麼打印list的所有內容;如果不是,那麼將節點加入list,然後繼續遞歸調用該函數,只不過,入口的參數變成了該節點的左子樹和右子樹。 程序如下 解答1:自己看書了   解答2:   //問題2:怎樣從頂部開始逐層打印二叉樹結點數據   void PrintAtLevel(BiTNode* root){       vector<BiTNode*> vector;       vector.push_back(root);       while(!vector.empty()){           BiTNode* tmp = vector.front();           if(tmp->lchild != NULL)               vector.push_back(tmp->lchild);           if (tmp->rchild != NULL)               vector.push_back(tmp->rchild);           cout << tmp->data << endl;           vector.pop_back();       }   }   //問題3:如何判斷一棵二叉樹是否是平衡二叉樹   int isBalencedTree(treeNode* root){       if (root == NULL)           return 0;       int depth1 = getDepth(root->lchild);       int depth2 = getDepth(root->rchild);       if (depth1 == depth2 || depth1 == depth2 + 1 || depth1 == depth2 - 1)           return 1;       else           return 0;       int flag1 = isBalencedTree(root->lchild);       int flag2 = isBalencedTree(root->rchild);       if (flag1 && flag2)           return 1;       else           return 0;   }   //問題4:設計一個算法,找出二叉樹上任意兩個節點的最近共同父結點,復雜度如果是O(n2)      則不得分。   int getPublicAncestors(treeNode* root,int key1,int key2){       treeNode* ptr = root;       int path1[1000];       int pathLen1 = 0;       while (ptr != NULL){           if (key1 == ptr->data){               path1[pathLen1] = ptr->data;               pathLen1 ++;               printArray(path1,pathLen1);               break;           }           else               if (ptr->data > key1){                   path1[pathLen1] = ptr->data;                   pathLen1 ++;                   ptr = ptr->lchild;               }               else                   if (ptr->data < key1){                       path1[pathLen1] = ptr->data;                       pathLen1 ++;                       ptr = ptr->rchild;                   }       }       ptr = root;           int path2[1000];           int pathLen2 = 0;           while (ptr != NULL){               if (key2 == ptr->data){                   path2[pathLen2] = ptr->data;                   pathLen2 ++;                   printArray(path2,pathLen2);                   break;               }               else                   if (ptr->data > key2){                       path2[pathLen2] = ptr->data;                       pathLen2 ++;                       ptr = ptr->lchild;                   }                   else                       if (ptr->data < key2){                           path2[pathLen2] = ptr->data;                           pathLen2 ++;                           ptr = ptr->rchild;                       }           }       int i = pathLen1 - 1;       //key1和key2有序,       if (key2 < key1){           key2 = key2^key1;           key1 = key2^key1;           key2 = key2^key1;       }       for (; i > 0; i --){           if (key1 < path1[i] && path1[i]< key2){               int result = path1[i];               return result;           }       }   }   //問題6:在二叉樹中找出和為某一值的所有路徑   void FindPath(treeNode* root, int path[],int pathLen,int expectedSum, int       currentSum){       if (root == NULL)           return;       currentSum += root->data;       path[pathLen] = root->data;       pathLen ++;       if (currentSum == expectedSum && root->lchild == NULL && root->rchild ==       NULL){           printArray(path,pathLen);       }       if (root->lchild != NULL){           FindPath(root->lchild,path,pathLen,expectedSum,currentSum);       }       if (root->rchild != NULL){               FindPath(root-      >rchild,path,pathLen,expectedSum,currentSum);           }       currentSum -= root->data;   }      //問題7:怎樣編寫一個程序,把一個有序整數數組放到二叉樹中?   void createTreeFromArray(int a[], int begin, int end, treeNode** root){       if (begin > end)           return;       else{           *root = (treeNode*) malloc(sizeof(treeNode));           int mid = (begin + end) / 2;           (*root)->data = a[mid];           (*root)->rchild = NULL;           (*root)->lchild = NULL;           createTreeFromArray(a, begin ,mid - 1, &(*root)->lchild);           createTreeFromArray(a, mid + 1 ,end, &(*root)->rchild);       }   }   //問題8:判斷整數序列是不是二叉搜索樹的後//序遍歷結果   int isPostTraverse(int a[], int begin ,int end){       if(begin >= end)           return 1;       else{           int root = a[end];           int lroot;           int i;           int location = begin;           for (i = begin; i < end ; i ++){               if(a[i] > root){                   location = i;                   lroot = a[i];                   break;               }           }           for (i = location + 1; i < end; i++){               if (a[i] < lroot){                   return 0;               }           }           int flag1 = isPostTraverse(a,begin,location -1);           int flag2 = isPostTraverse(a,location,end - 1);           if (flag1 && flag2)               return 1;           else               return 0;       }   }   //問題9:求二叉樹的鏡像   void changeMirror(treeNode** root){       if ( *root == NULL)           return;       else{           treeNode* temp = (*root)->lchild;           (*root)->lchild = (*root)->rchild;           (*root)->rchild = temp;           changeMirror(&(*root)->lchild);           changeMirror(&(*root)->rchild);       }   }   //問題10:10.一棵排序二叉樹(即二叉搜索樹BST),令 f=(最大值+最小值)/2,設計一個算      //法,找出距離f值最近、大於f值的結點。復雜度如果是O(n2)則不得分。   int findNearMid(treeNode** root){       treeNode* ptr = *root;       int min, max;       while (ptr != NULL){           min = ptr->data;           ptr = ptr->lchild;       }       printf("the min is %d\n",min);       ptr = *root;       while (ptr != NULL){           max = ptr->data;           ptr = ptr->rchild;       }       printf("the max is %d\n",max);       int half = (min + max) >> 1;       printf("half is %d\n",half);       ptr = *root;       while (1){           if (ptr->data < half){               ptr = ptr->rchild;           }           else               if (ptr->data > half){                   int result = ptr->data;                   return result;               }               else               {                   return (ptr->rchild)->data;               }       }   }   //問題12:打印二叉樹中的所有路徑(與題目5很相似)   void printPathsRecur(treeNode* node, int path[], int pathLen) {       if (node == NULL)           return;       // append this node to the path array       path[pathLen] = node->data;       pathLen++;       // it's a leaf, so print the path that led to here       if (node->lchild == NULL && node->rchild == NULL) {           printArray(path, pathLen);       } else {           // otherwise try both subtrees           printPathsRecur(node->lchild, path, pathLen);           printPathsRecur(node->rchild, path, pathLen);       }   }      void printPaths(treeNode* node) {       int path[1000];       printPathsRecur(node, path, 0);   }   //用到的輔助函數:   /**   * 求二叉樹的深度   */   int getDepth(tNode root) {       if (root == NULL)           return 0;       else           return getDepth(root->lchild) > getLeaf(root->rchild) ? 1 +       getDepth(                   root->lchild) : 1 + getDepth(root->rchild);       //  {       //      int depthLchild = 1 + getDepth(root->lchild);       //      int depthRchild = 1 + getDepth(root->rchild);       //      return depthLchild > depthRchild ? depthLchild:       depthRchild;       //  }   }   /**   * 打印數組   */   void printArray(int ints[], int len) {       int i;       for (i = 0; i < len; i++) {           printf("%d ", ints[i]);       }       printf("\n");   }        

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved