二叉樹轉雙向鏈表問題
問題描述
* 問題描述
* 輸入一棵二叉搜索樹,將該二叉搜索樹轉換成一個排序的雙向鏈表。“要求不能創建任何新的結點”,只能調整樹中結點指針的指向。例如輸入前序遍歷爲
* 10、6、4、8、14、12、16的二叉搜索樹,其輸出的轉換後排序雙向鏈表爲:4、6、8、10、12、14、16
問題分析
* 問題分析:
* 在二叉樹中,每個結點都有兩個指向子結點的指針。在雙向鏈表中,每個結點也有兩個指針,它們分別是指向前一個結點和後一個結點。由於這兩個結點的
* 結構相似,同時二叉搜索樹也是一種排序的數據結構,因此在理論上有可能實現二叉搜索樹和排序的雙向鏈表的轉換。在二叉搜索樹中,左子結點的值總是小於父結點
* 的值,有子結點的值總是大於父結點的值。因此在轉換成排序的雙向鏈表時,原先指向左子結點的指針調整爲鏈表中指向前一個結點的指針,原先指向右子結點
* 的指針調整爲鏈表中指向後一個結點指針。
* 由於要求轉換後的鏈表是排序好的,因此可以用中序遍歷來操作,對於二叉查找樹而言,其中序遍歷序列就是從小到大排序的。當遍歷到根結點的時候,我們把
* 樹看成三個部分:值爲10的根結點,根結點值爲6的左子樹,根結點值爲14的右子樹。根據排序鏈表的定義,值爲10的結點將和它的左子樹的最大一個結點(值爲8的結點)
* 鏈接起來,同時它將和右子樹最小的結點(即值爲12的結點)鏈接起來。
public class Code027 {
public static void main(String[] args){
BinaryTreeNode node1=new BinaryTreeNode(10);
BinaryTreeNode node2=new BinaryTreeNode(6);
BinaryTreeNode node3=new BinaryTreeNode(14);
BinaryTreeNode node4=new BinaryTreeNode(4);
BinaryTreeNode node5=new BinaryTreeNode(8);
BinaryTreeNode node6=new BinaryTreeNode(12);
BinaryTreeNode node7=new BinaryTreeNode(16);
BinaryTreeNode pRoot1=node1;
node1.pLeft=node2;node1.pRight=node3;
node2.pLeft=node4;node2.pRight=node5;
node3.pLeft=node6;node3.pRight=node7;
// BinaryTreeNode pNowRoot=Convert(pRoot1);
BinaryTreeNode pNowRoot=ConvertBSTToBiList(pRoot1);
while (pNowRoot!=null){
System.out.print(pNowRoot.value+" ");
pNowRoot=pNowRoot.pRight;
}
}
//定義雙向鏈表的左邊頭結點和右邊頭結點,初始化爲null
static BinaryTreeNode leftHead=null;
static BinaryTreeNode rightHead=null;
private static BinaryTreeNode Convert(BinaryTreeNode pRootOfTree){
//遞歸調用葉子結點的左右結點返回null
if(pRootOfTree==null){
return null;
}
//第一次運行時,它會使最左邊的葉子結點爲鏈表的第一個節點
Convert(pRootOfTree.pLeft);
if(rightHead==null){
leftHead=pRootOfTree;
rightHead=pRootOfTree;
}else {
//把根結點插入到雙向鏈表右邊,rightHead向後移動
rightHead.pRight=pRootOfTree;
pRootOfTree.pLeft=rightHead;
rightHead=pRootOfTree;
}
//把右葉子結點也插入到雙向鏈表(rightHead已確定,直接插入)
Convert(pRootOfTree.pRight);
//返回左邊頭結點,也可以返回右邊頭結點
return leftHead;
}
//非遞歸法:藉助棧來存儲中序遍歷的結果順序
private static BinaryTreeNode ConvertBSTToBiList(BinaryTreeNode pRoot){
if(pRoot==null){
return null;
}
//定義棧用於存儲中序遍歷的結點順序
Stack<BinaryTreeNode> stack=new Stack<>();
BinaryTreeNode p=pRoot;
BinaryTreeNode pre=null;//用於保存中序遍歷的上一個結點
boolean isFirst=true;
while (p!=null|| !stack.isEmpty()){
while (p!=null){
stack.push(p);
p=p.pLeft;
}
//找到左子樹的最左葉子結點,即爲中序遍歷的第一個結點
p=stack.pop();
if(isFirst){
pRoot=p;//將中序遍歷列中的第一個節點記爲pRoot
pre=pRoot;
isFirst=false;
}else {
pre.pRight=p;
p.pLeft=pre;
pre=p;
}
p=p.pRight;
}
return pRoot;
}
//定義二叉樹的結點類
private static class BinaryTreeNode{
int value;
BinaryTreeNode pLeft;
BinaryTreeNode pRight;
public BinaryTreeNode() {
}
public BinaryTreeNode(int value) {
this.value = value;
}
}
}