Morris遍歷演算法學習筆記(空間複雜度為1的二叉樹遍歷方式)
阿新 • • 發佈:2021-01-12
引言
期末考試結束在家的時候有外校的同學問了我一道資料結構考試題,要求不用棧和遞迴,實現樹的遍歷。當然,我想到了用迭代演算法來做,但是沒想出來怎麼做。最近幾天刷題連續刷到要求用迭代實現遍歷二叉樹的題,打算記錄一下morris演算法的學習過程。
原理
morris演算法巧妙地將每個葉子節點都連線到了記錄完它自己後,需要記錄的下一個節點,形成一個迴路,這樣就可以通過迭代完成遍歷,而不需要遞迴。這種方法不僅時間複雜度是n,而且空間複雜度是1。
中序遍歷:
每次遍歷一個節點,設為root
如果root沒有左子樹,那麼直接將root的值記錄下來,然後令root=root->right
如果root有左子樹,那麼將找到左子樹的最右的節點,記錄為N,將N的right連結到root上(為了回溯)然後令root=root->left,如果N的right已經連到了root,證明root的左子樹已經遍歷完成,將root的值記錄下來然後令root=root->right
程式碼
下面我貼出的是中序遍歷的morris程式碼,將遍歷得到的節點值記錄到一個vector中
1 class Solution { 2 public: 3 vector<int> inorderTraversal(TreeNode* root) { 4 vector<int> ret; 5 TreeNode* N; 6 while(root!=NULL) 7 { 8 if(root->left!=NULL)//如果左子樹為空,直接把節點值加入向量中,開始進行右子樹的遍歷9 { 10 N=root->left; 11 while(N->right!=NULL&&N->right!=root)//找到標記的點(左子樹的最右節點) 12 { 13 N=N->right; 14 } 15 if(N->right==NULL) 16 { 17 N->right=root;18 root=root->left; 19 } 20 else if(N->right==root)//如果標記節點的右節點已經是root了,證明左子樹已經遍歷完成,直接將root放進向量中 21 { 22 ret.push_back(root->val); 23 N->right=NULL; 24 root=root->right; 25 } 26 } 27 else if(root->left==NULL) 28 { 29 ret.push_back(root->val); 30 root=root->right; 31 } 32 } 33 return ret; 34 } 35 };
結尾
這個演算法不太好理解,但是通過一個高度為3的滿二叉樹,把每個葉子節點的回溯指向畫出來,然後按照演算法思想自己遍歷一次就可以發現這個演算法的巧妙之處,而且也可以輕鬆理解。希望我的學習筆記可以為您提供幫助。