二叉搜尋樹轉換成有序的雙向迴圈鏈表(一)

來源:互聯網
上載者:User
題目描述

給定一棵二叉排序樹(BST),將該樹轉換成一棵雙向迴圈鏈表。請看下面的圖示說明,你可以更清楚的瞭解題意。

BST的結構定義如下:

struct node {    int data;    struct node* left;    struct node* right;};typedef struct node Node;

                                     圖1)一棵儲存1-5的二叉搜尋樹(BST)

 

        圖2)根據上面的BST轉換得到的有序迴圈鏈表。其中,樹的左右孩子指標替換成了pre和next指標,分別指向鏈表的前一個和後一個結點。

 

 分析看到這個題目,相信大多數人第一反應就是中序遍曆這棵二叉樹,同時改變樹中結點的left和right指標。這裡需要額外考慮的是如何將最後一個結點的right指標指向第一個結點,如所展示的那樣。                                             圖3)一個雙向迴圈鏈表以中序遍曆遍曆一棵二叉樹的時候,每遍曆到一個結點,我們就可以修改該結點的left指標指向前一個遍曆到的結點,因為在後續操作中我們不會再用到left指標;與此同時,我們還需要修改前一個遍曆結點的right指標,讓前一個遍曆結點的right指標指向當前結點。比如我們遍曆到結點2,則我們修改結點2的left指標指向結點1,同時需要修改結點1的right指標指向結點2。 需要注意一點,這裡的前一個遍曆結點不是當前結點的父結點,而是當前結點的前一個比它小的結點。
看似問題已經解決,慢著,我們其實落下了重要的兩步。1)我們沒有對頭結點head賦值。 2)最後一個結點的right指標沒有指向第一個結點。
解決這兩個問題的方案非常簡單:在每次遞迴調用的時候,更新 當前遍曆結點的right指標讓其指向頭結點head,同時更新 頭結點head的left指標讓其指向當前遍曆結點。當遞迴調用結束的時候,鏈表的頭尾結點會指向正確的位置。不要忘記只有一個結點的特殊情況,它的left和right指標都是指向自己。      圖4)只有一個結點的雙向迴圈鏈表這個解法非常的精巧,因為該演算法是對中序遍曆的一個改進,因此它的時間複雜度為O(N),N為結點數目。當然,相比中序遍曆,我們在每次遞迴調用過程中增加了額外的賦值操作。
// 這是一個改進的中序遍曆// prev (初始化為NULL) 用於跟蹤前一個遍曆結點// 當遞迴結束時,head指向鏈表的頭部void treeToDoublyList(Node *p, Node *& prev, Node *& head) {  if (!p) return;  treeToDoublyList(p->left, prev, head);  // 當前結點p的left指向前一個結點prev  p->left = prev;  if (prev)    prev->right = p;  //前一個結點的right指向當前結點  else    head = p; //如果前面沒有結點,則設定head為當前結點(當前結點為最小的結點)。  //遞迴結束後,head的left指標指向最後一個結點,最後一個結點的右指標指向head結點。注意儲存p的right指標,因為在後面代碼中會修改該指標。  Node *right = p->right;  head->left = p;  p->right = head;  prev = p;//更新前一個結點  treeToDoublyList(right, prev, head); } //主函數,初始化prev和head為NULLNode* treeToDoublyList(Node *root) {  Node *prev = NULL;  Node *head = NULL;  treeToDoublyList(root, prev, head);  return head;}

代碼解析這個遞迴演算法挺複雜的,還是從函數功能上來理解會容易懂一點。函數treeToDoublyList(Node *p, Node *&prev, Node *&head)的功能是將以p為根結點的樹轉換成有序的雙向迴圈鏈表。函數執行前,prev總是指向遍曆到p之前的前一個結點。函數執行完成後,prev指向p,head指向鏈表頭結點。以上面圖中的二叉樹為例,treeToDoublyList(Node *p, Node *&prev, Node *&head)過程如下:根結點為4,調用treeToDoublyList(p->left, prev, head)遍曆完左子樹後,左子樹構成有序雙向迴圈鏈表1=2=3,prev指向的是結點3,head指向當前雙向迴圈鏈表的頭結點1。更新p->left=prev,即4的left指標指向3,設定prev->right=p,即3的right指標指向4。同時更新head結點1的left為節點4,4的right指標更新為1,則此時雙向迴圈鏈表變成1=2=3=4,接下來遞迴遍曆右子樹結點,保持雙向迴圈鏈表的性質。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.