好不容易又到周五了,周末終於可以休息休息了。寫這一篇隨筆只是心血來潮,下午問了一位朋友PAT考的如何,順便看一下他考的試題,里面有最后一道題,是關於給出中序遍歷和后序遍歷然后求一個層次遍歷。等等,我找一下鏈接出來......
1127. ZigZagging on a Tree (30):https://www.patest.cn/contests/pat-a-practise/1127
突然想起以前學數據結構的時候如果給出一個中序遍歷和一個后序遍歷然后讓你畫出樹的結構或求出先序遍歷之類的題目,如果用筆來畫,三下五除二能夠一下子就畫出來,但關於用語言編寫出來卻從來沒有想過,真是慚愧,所以這篇隨筆的內容思維可能比較簡單低階,請大家包涵。
所以想試一下能不能寫一寫,加之最近在補習一些算法和數據結構之類的題目,可以作為一個練手的題目。想不到要動手之前理清一下構造的過程,最后卻有些明朗的感覺,這也是我想寫下這篇隨筆的原因,雖然簡單,但很有意義。好,說了這么多廢話...下面開始:
對於一棵樹的中序遍歷,根節點肯定處於遍歷結果的中間(假設這棵樹有左子樹),后序遍歷的時候根節點肯定是最后一個遍歷的元素。所以可以輕易得到根在中序遍歷中的位置,根據中序遍歷的性質,以根為中點往后遍歷到的元素就是這棵樹的右子樹元素,往前遍歷到的就是這棵樹的左子樹元素。而后續遍歷也是把這棵樹的左子樹全部遍歷完整之后再來遍歷右子樹,因此在后續遍歷中,左子樹和右子樹的元素也是有明顯的界限。而對於根節點的左節點和右節點也是同樣的道理。舉個例子
所以我們從最初的遍歷順序開始,找出后續遍歷的最后一個元素在中序遍歷中的位置,然后以這個位置為重點,往右的遍歷元素為A,往左的遍歷元素為B,根據A和B的長度可以確定在后續遍歷中的遍歷元素邊界,對A和B進行上一步的操作,直到所有元素遍歷完成。代碼:
Node *getRoot(int* inorder,int* postorder,int ix,int iy,int px,int py){ Node *node = new Node(postorder[py]); int p = findElem(inorder,postorder[py],ix,iy); if(-1 != p){ int lix,liy,lpx,lpy,rix,riy,rpx,rpy; if(p == iy)node->right = NULL; else{ rix = p+1; riy= iy; rpy = py-1; rpx = rpy - (riy-rix); node->right = getRoot(inorder,postorder,rix,riy,rpx,rpy); } if(p == ix) node->left = NULL; else{ lix = ix; liy = p -1; lpx = px; lpy = px + (liy-lix); node->left = getRoot(inorder,postorder,lix,liy,lpx,lpy); } return node; }else return NULL; } void MidTraverse(Node *root){ if(NULL != root){ cout<<root->val<<" "; MidTraverse(root->left); MidTraverse(root->right); } } int main(){ int count; cin>>count; int *inorder = new int[count]; int *postorder = new int[count]; for(int i =0;i<2;i++){ for(int j=0;j<count;j++){ int in; cin>>in; if(0==i) inorder[j] = in; else postorder[j] = in; } } Node *root = getRoot(inorder,postorder,0,count-1,0,count-1); if(NULL !=root) MidTraverse(root); }
節點定義為:
typedef struct _Node{ int val; struct _Node *left,*right; _Node(int _val):val(_val),left(NULL),right(NULL){} }Node;
運行代碼,最后結果在意料之內:
深圳的工作壓力強行把市民的生活節奏拉的飛快,上了一周的班心緒有些煩躁,下班出了公司的門卻意外地迎來了樹葉和泥土的味道,是一場雨清澈了整片空氣。