標籤:des style blog http color strong
轉載請註明出處:http://blog.csdn.net/ns_code/article/details/28113959
劍指offer上的最後一題了,一個遞迴函式調了一下午,才得到正確的結果。
-
題目描寫敘述:
-
給定一棵樹,同一時候給出樹中的兩個結點,求它們的最低公用祖先。
-
輸入:
-
輸入可能包括多個測試例子。
對於每一個測試案例,輸入的第一行為一個數n(0<n<1000),代表測試例子的個數。
當中每一個測試例子包括兩行,第一行為一個二叉樹的先序遍曆序列,當中左右子樹若為空白則用0取代,當中二叉樹的結點個數node_num<10000。
第二行為樹中的兩個結點的值m1與m2(0<m1,m2<10000)。
-
輸出:
-
相應每一個測試案例,
輸出給定的樹中兩個結點的最低公用祖先結點的值,若兩個給定結點無最低公用祖先,則輸出“My God”。
-
例子輸入:
-
21 2 4 6 0 0 7 0 0 5 8 0 0 9 0 0 3 0 06 81 2 4 6 0 0 7 0 0 5 8 0 0 9 0 0 3 0 06 12
-
例子輸出:
-
2My God
這類的題目,方法蠻多的,思路也不難理解,基本都是各種遍曆的變種,主要是寫代碼,尤其基於遞迴的代碼。
首先假設是二叉排序樹自然不用說了,推斷的一句就是該節點的值是否位於輸入的這兩個節點之間,能夠用前序走訪來做。
假設是普通的樹或者二叉樹,解題思路是一樣的,能夠考慮前序走訪,得到兩個路徑,用鏈表或數組儲存起來,然後找出兩條路徑的最後一個公用節點就可以。也能夠後序遍曆的方式,遍曆到輸入的節點時,將該節點及其後面遍曆到的節點都儲存到一個鏈表或數組中,然後找出兩條路徑的第一個公用機節點就可以。
以下採用的是前序走訪,並用數組儲存路徑的代碼。
#include<stdio.h>#include<stdlib.h>#include<stdbool.h>typedef struct BTNode{struct BTNode *lchild;struct BTNode *rchild;int data;}BTNode,*BTree;/*前序走訪找出根節點到資料域為val的節點路徑,儲存在path數組中,這裡index是儲存到path數組中的元素的下標,*len用來儲存路徑長度,假設能找到val,則返回ture,找不到則返回false*/bool GetPreTraversePath(BTree pTree,int val,int *path,int index,int *len){if(pTree == NULL){*len = 0;return false;}path[index] = pTree->data;if(pTree->data == val){*len = index+1;return true;}else{bool can;can = GetPreTraversePath(pTree->lchild,val,path,index+1,len);if(!can)can = GetPreTraversePath(pTree->rchild,val,path,index+1,len);return can;}}/*擷取兩個路徑的最後一個公用節點,因為對樹的先序遍曆的結果中,前面一定有些節點同樣,因此一定能找到最後一個同樣節點*/int GetFirstCommonNode(int *path1,int len1,int *path2,int len2){int shortLen = len1<len2 ? len1:len2;int i;for(i=0;i<shortLen;i++){if(path1[i] != path2[i])break;}return path1[i-1];}/*依據先序遍曆序列建立二叉樹,因為可能改變根節點的指向,因此傳入BTNode的二級指標*/void CreateBTree(BTree *pRoot){int data;scanf("%d",&data);if(data == 0)*pRoot = NULL;else{*pRoot = (BTree)malloc(sizeof(BTNode));if(*pRoot == NULL)exit(EXIT_FAILURE); (*pRoot)->data = data;(*pRoot)->lchild = NULL;(*pRoot)->rchild = NULL;CreateBTree(&((*pRoot)->lchild));CreateBTree(&((*pRoot)->rchild));}}/*銷毀二叉樹*/void DestroyBTree(BTree pRoot){if(pRoot != NULL){if(pRoot->lchild != NULL)DestroyBTree(pRoot->lchild);if(pRoot->rchild != NULL)DestroyBTree(pRoot->rchild);free(pRoot);pRoot = NULL;}}int main(){int path1[10000];int path2[10000];int n;while(scanf("%d",&n) != EOF){int i;for(i=0;i<n;i++){BTree pRoot = NULL;CreateBTree(&pRoot);int val1,val2;scanf("%d %d",&val1,&val2);int len1,len2;bool can1 = GetPreTraversePath(pRoot,val1,path1,0,&len1);bool can2 = GetPreTraversePath(pRoot,val2,path2,0,&len2);if(can1 && can2)printf("%d\n",GetFirstCommonNode(path1,len1,path2,len2));elseprintf("My God\n");DestroyBTree(pRoot);}}return 0;}
/**************************************************************
Problem: 1509
User: mmc_maodun
Language: C
Result: Accepted
Time:130 ms
Memory:920 kb
****************************************************************/ PS:尋找路徑的遞迴代碼調了一個下午,總算搞定了,每次碰到關於樹的問題,一般都是三種遍曆方式的變種來實現,自然想到遞推,有些寫著非常easy,有些寫著總非常糾結,尤其要返回bool變數的時候,還是太菜,回頭要抽個時間把二叉樹的遞迴實現的一些題目好好總結下。