1. 程式人生 > >輸入一棵二叉搜尋樹,將該二叉搜尋樹轉換成一個排序的雙向連結串列(劍指offer)

輸入一棵二叉搜尋樹,將該二叉搜尋樹轉換成一個排序的雙向連結串列(劍指offer)

題目

輸入一棵二叉搜尋樹,將該二叉搜尋樹轉換成一個排序的雙向連結串列。要求不能建立任何新的結點,只能調整樹中結點指標的指向。
分析:
在二叉搜尋樹中,每個結點都有兩個分別指向其左、右子樹的指標,左子樹結點的值總是小於父結點的值,右子樹結點的值總是大於父結點的值。在雙向連結串列中,每個結點也有兩個指標,它們分別指向前一個結點和後一個結點。所以這兩種資料結構的結點是一致,二叉搜尋樹和雙向連結串列,只是因為兩個指標的指向不同而已
舉個例子,如下圖中的二叉搜尋樹,轉換後的雙向連結串列為:
在這裡插入圖片描述
為了減少指標的變換次數,並讓操作更加簡單,在轉換成排序雙向連結串列時,原先指向左子結點的指標調整為連結串列中指向前一個結點的指標,原先指向右子結點的指標調整為連結串列中指向下一個結點的指標。
由於要求連結串列是有序的,可以藉助二叉樹中序遍歷,因為中序遍歷演算法的特點就是從小到大訪問結點。當遍歷訪問到根結點時,假設根結點的左側已經處理好,只需將根結點與上次訪問的最近結點(左子樹中最大值結點)的指標連線好即可。進而更新當前連結串列的最後一個結點指標。同時中序遍歷過程正好是轉換成連結串列的過程,可採用遞迴方法處理。
在這裡插入圖片描述

法一:遞迴版本

(不理解中序遍歷的遞迴與非遞迴可以看我之前的文章

public class Convert {
	// 雙向連結串列的左邊頭結點和右邊頭節點
	TreeNode leftHead = null;
	TreeNode rightHead = null;

	public TreeNode convert(TreeNode pRootOfTree){
		// 遞迴呼叫葉子節點的左右節點返回null
		if (pRootOfTree == null)
			return null;
		// 第一次執行時,它會使最左邊葉子節點為連結串列第一個節點
		convert(pRootOfTree.
left); if (rightHead == null) { leftHead = pRootOfTree; rightHead = pRootOfTree; } else { // 把根節點插入到雙向連結串列右邊,rightHead向後移動 rightHead.right = pRootOfTree; pRootOfTree.left = rightHead; rightHead = pRootOfTree; } // 把右葉子節點也插入到雙向連結串列(rightHead已確定,直接插入) convert(pRootOfTree.right)
; // 返回左邊頭結點 return leftHead; } }

法二:非遞迴版本

1.核心是中序遍歷的非遞迴演算法。(不理解中序遍歷的遞迴與非遞迴可以看我之前的文章
2.修改當前遍歷節點與前一遍歷節點的指標指向。

 public TreeNode ConvertBSTToBiList(TreeNode root) {
        if(root==null)
            return null;
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode p = root;
        TreeNode pre = null;// 用於儲存中序遍歷序列的上一節點
        boolean isFirst = true;
        while(p!=null||!stack.isEmpty()){
            while(p!=null){
                stack.push(p);
                p = p.left;
            }
            p = stack.pop();
            if(isFirst){
                root = p;// 將中序遍歷序列中的第一個節點記為root
                pre = root;
                isFirst = false;
            }else{
                pre.right = p;
                p.left = pre;
                pre = p;
            }      
            p = p.right;
        }
        return root;
    }

參考

https://blog.csdn.net/yanxiaolx/article/details/52073221