《劍指Offer》讀書筆記---面試題6:重建二叉樹

來源:互聯網
上載者:User

題目:輸入某二叉樹的前序走訪和中序遍曆的結果,請重建出該二叉樹。假設輸入的前序走訪和中序遍曆的結果中都不含重複的數字。例如輸入前序走訪序列{1,2,4,7,3,5,6,8}和中序遍曆序列{4,7,2,1,5,3,8,6},則重建出二叉樹並輸出它的頭結點。二叉樹結點的定義為:

struct BinaryTreeNode{intm_nValue ;BinaryTreeNode*m_pLeft ;BinaryTreeNode*m_pRight ;} ;

一開始看到這道題的時候還真沒有想法,後來也的確沒有什麼想法,基礎太弱了,果斷去看答案了。


先寫一下書上面的思路:

在二叉樹的前序走訪序列中,第一個數字總是樹的根結點的值。但在中序遍曆序列中,根結點的值在序列的中間,左子樹的結點的值位於根結點的值的左邊,而右子樹的結點的值位於根結點的值的右邊。因此我們需要掃描中序遍曆序列,才能找到根結點的值。如題目給出的序列,前序走訪中的第一個數字1就是根結點的值。掃描中序遍曆序列,就能確定根結點的值的位置。根據中序遍曆的特點,在根結點的值1前面的3個數字都是左子樹結點的值,位於1後面的數字都是右子樹結點的值。這樣我們就在前序走訪和中序遍曆兩個序列中,分別找到了左右子樹對應的子序列。因此,可以用同樣的方法去構建左右子樹。也就是說,接下來的事情可以用遞迴的方法去完成。

詳見代碼:

#include<cstdio>#include<iostream>struct BinaryTreeNode{intm_nValue ;BinaryTreeNode*m_pLeft ;BinaryTreeNode*m_pRight ;} ;BinaryTreeNode* Construct(int* preorder,int* inorder,int length) ;BinaryTreeNode* ConstructCore(int* startPreorder,int *endPreorder, int* startInorder,int * endInorder) ;void PreOrderPrintTree(const BinaryTreeNode *pNode) ;int main(void){int nPreOrder[] = {1,2,4,7,3,5,6,8} ;int nInOrder[] = {4,7,2,1,5,3,8,6} ;BinaryTreeNode* root = Construct(nPreOrder,nInOrder,sizeof(nPreOrder)/sizeof(int)) ;PreOrderPrintTree(root) ;printf("\n") ;return 0 ;}//前序走訪函數,用來驗證結果void PreOrderPrintTree(const BinaryTreeNode *pNode) {if(pNode != NULL){printf("%d ",pNode->m_nValue) ;PreOrderPrintTree(pNode->m_pLeft) ;PreOrderPrintTree(pNode->m_pRight) ;}}//從前序走訪和中序遍曆,重建二叉樹BinaryTreeNode* Construct(int* preorder,int* inorder,int length)  //length為序列的長度{if(preorder == NULL || inorder == NULL || length <= 0){returnNULL ;}return ConstructCore(preorder,preorder + length - 1 ,inorder,inorder + length - 1) ;}//核心函數BinaryTreeNode* ConstructCore(int* startPreorder,int* endPreorder, int* startInorder,int* endInorder){//前序走訪序列的第一個數字是根結點的值int rootValue = startPreorder[0] ;BinaryTreeNode* root = new BinaryTreeNode() ;//構造一個結點root->m_nValue = rootValue ;root->m_pLeft = root->m_pRight = NULL ;if(startPreorder == endPreorder) {if(startInorder == endInorder&& *startPreorder == *startInorder) //只有一個結點{return root ;}else throw std::exception("Invalid input.") ;}//在中序遍曆中找到根結點的值int* rootInorder = startInorder ;while(rootInorder <= endInorder && *rootInorder != rootValue){++rootInorder ;}//如果根結點等於中序遍曆的末結點,則資料出錯if(rootInorder == endInorder && *rootInorder != rootValue){throw std::exception("Invalid input.") ;}int leftLength = rootInorder - startInorder ;//中序遍曆中根結點左結點數int* leftPreorderEnd = startPreorder + leftLength ; //前序走訪中左子樹結點的下一個位置if(leftLength > 0){//構建左子樹,startPreorder+1為左子樹的第一個結點,rootInorder-1為左子樹的最後一個結點root->m_pLeft = ConstructCore(startPreorder + 1,leftPreorderEnd,startInorder,rootInorder - 1) ;}if(leftLength < endPreorder - startPreorder){//構建右子樹root->m_pRight = ConstructCore(leftPreorderEnd + 1 ,endPreorder,rootInorder + 1,endInorder) ;}return root ;}

然後,自己類比了一下有後序遍曆序列和踱遍曆序列的情況,如何去構建二叉樹。

#include<iostream>#include<cstdio>struct BinaryTreeNode{int m_nValue ;BinaryTreeNode* m_pLeft ;BinaryTreeNode* m_pRight ;} ;BinaryTreeNode* Construct(int *postorder,int* inorder,int length) ;BinaryTreeNode* ConstructCore(int *startPostorder,int *endPostorder,int* startInorder,int *endInorder) ;void PrintPreOrder(BinaryTreeNode *pNode) ;int main(void){int nPostOrder[] = {7,4,2,5,8,6,3,1} ;int nInOrder[] = {4,7,2,1,5,3,8,6} ;BinaryTreeNode* root = Construct(nPostOrder,nInOrder,sizeof(nPostOrder)/sizeof(int)) ;PrintPreOrder(root) ;printf("\n") ;return 0 ;}BinaryTreeNode* Construct(int *postorder,int* inorder,int length) {if(NULL == postorder || NULL == inorder || length <= 0)  {return NULL ;}return ConstructCore(postorder,postorder + length -1 ,inorder,inorder + length - 1)  ;}void PrintPreOrder(BinaryTreeNode *pNode) {if(pNode != NULL){PrintPreOrder(pNode->m_pLeft) ;PrintPreOrder(pNode->m_pRight) ;printf("%d ",pNode->m_nValue) ;}}BinaryTreeNode* ConstructCore(int *startPostorder,int *endPostorder,int* startInorder,int *endInorder) {int nValue = *endPostorder ;BinaryTreeNode* root = new BinaryTreeNode ;root->m_nValue = nValue ;root->m_pLeft = root->m_pRight = NULL ;if(startPostorder == endPostorder)  //葉子結點{if(startInorder == endInorder &&   //兩個序列都要判斷,否則就是無效僌 *startPostorder == *endPostorder){return root ;}else{throw std::exception("Invalid input.") ;}}int* rootInorder = startInorder ;while(rootInorder <= endInorder && *rootInorder != nValue){rootInorder++ ;}if(*rootInorder != nValue && rootInorder == endInorder){throw std::exception("Invalid input.") ;}int nRightLength = endInorder - rootInorder ;int* rightPostorderStart = endPostorder - nRightLength ;if(nRightLength > 0){//構建右子樹root->m_pRight = ConstructCore(rightPostorderStart,endPostorder - 1,rootInorder + 1,endInorder) ;}if(startInorder < rootInorder){//構建左子樹 root->m_pLeft = ConstructCore(startPostorder,rightPostorderStart-1,startInorder,rootInorder - 1) ;}return root ;}




聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.