package cn.com.amazon.basic.one;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/**
1.把二元查找树转变成排序的双向链表
题目:
输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。
要求不能创建任何新的结点,只调整指针的指向。
10
/ \
6 14
/ \ / \
4 8 12 16
转换成双向链表
4=6=8=10=12=14=16。
首先我们定义的二元查找树 节点的数据结构如下:
struct BSTreeNode
{
int m_nValue; // value of node
BSTreeNode *m_pLeft; // left child of node
BSTreeNode *m_pRight; // right child of node
};
思路汇总:
(1)每访问到一个parent,递归左子树,递归右子树,连接左子树的最左边,右子树的最右边与根节点的结合处。故递归函数必须标明当前子树左右情况。
(2)中序遍历树,记录一个pre,然后每访问到一个节点,就将其加入双向链表中,具体即为与pre的操作。
*/
public class BSTree implements Cloneable, Serializable {
/**
* v0.8
*/
private static final long serialVersionUID = -7240326774488306261L;
private BSNode m_root; // 根节点
private BSNode tempListNode; // 创建doubleList的时候使用的临时变量
private BSNode tempListHead; // 创建doubleList的时候使用的临时变量
public void setM_root(BSNode mRoot) {
m_root = mRoot;
}
public BSNode getM_root() {
return m_root;
}
/**
* 深拷贝
*/
public Object clone() {
try {
// 没有去想树的节点拷贝算法,先用这种简便方法,再复杂的类型拷贝也不怕,不过所有相关类都必须是Serializable
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
oos.close();
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
Object ob = ois.readObject();
ois.close();
return (BSTree) ob;
} catch (Exception e) {
System.out.println("CloneNotSupportedException: " + e);
e.printStackTrace();
}
return null;
}
/**
* 增加子节点
* @param 二元查找树节点
*/
public synchronized void addNode(BSNode node) {
if (null == this.m_root) {
this.m_root = node;
return;
}
BSNode tempNode = this.m_root;
while (true) {
if (node.getM_nValue() > tempNode.getM_nValue()) { // 大于父节点
if (null == tempNode.getM_pRight()) {
tempNode.setM_pRight(node);
return;
} else {
tempNode = tempNode.getM_pRight();
continue;
}
} else if (node.getM_nValue() < tempNode.getM_nValue()) { // 小于父节点
if (null == tempNode.getM_pLeft()) {
tempNode.setM_pLeft(node);
return;
} else {
tempNode = tempNode.getM_pLeft();
continue;
}
} else { // 等于父节点
return;
}
}
}
/**
* 生成双向链表
* @return 双向链表
* @throws CloneNotSupportedException
*/
public synchronized BSDoubleList changeToDoubleList() {
BSTree tempTree = (BSTree) this.clone(); // 临时树,替死鬼,被转换得面目全非,垃圾回收了吧...
// 其实改为changeTreeToDoubleList(this.getM_root());才符合题意,不过个人喜欢使用深拷贝,不破坏原来的树
if (null != tempTree) {
changeTreeToDoubleList(tempTree.getM_root());
}
BSDoubleList dlist = new BSDoubleList();
dlist.setHead(tempListHead);
return dlist;
}
private void changeTreeToDoubleList(BSNode node) {
if (null == node) {
return;
}
if (null != node.getM_pLeft()) {
changeTreeToDoubleList(node.getM_pLeft());
}
// -------------转换---------------
node.setM_pLeft(tempListNode);
if (null == tempListNode){
tempListHead = node;
} else {
tempListNode.setM_pRight(node);
}
//---------------------------------
tempListNode = node;
if (null != node.getM_pRight()) {
changeTreeToDoubleList(node.getM_pRight());
}
}
/**
* 打印中序遍历
*/
public synchronized void print() {
if (null == this.m_root) {
System.out.print("HashCode: " + this.hashCode() + "; 空树;");
return;
}
System.out.print("HashCode: " + this.hashCode() + "; 树: ");
print(this.m_root);
System.out.println();
}
private void print(BSNode node) {
if (null != node) {
print(node.getM_pLeft());
System.out.print(node.getM_nValue() + " ");
print(node.getM_pRight());
}
}
}