您的位置:首页 > 其它

【算法导论学习-24】二叉树专题2:二叉搜索树(Binary Search Tree,BST)

2014-08-28 14:18 561 查看

一、 二叉搜索树(Binary SearchTree,BST)

对应《算法导论》第12章。相比一般二叉树,BST满足唯一的条件:任意节点的key>左孩子的key,同时<右孩子的key。

1. 节点类:

public class BinarySearchTreesNode<T> {
private int key;
private T satelliteData;
private BinarySearchTreesNode<T> parent, leftChild, rightChild;

public BinarySearchTreesNode(int key, T satelliteData) {
// TODO 自动生成的构造函数存根
this.key = key;
this.satelliteData = satelliteData;
parent = leftChild = rightChild = null;
}

public T getSatelliteData() {
return satelliteData;
}

public void setSatelliteData(T satelliteData) {
this.satelliteData = satelliteData;
}

public BinarySearchTreesNode<T> getParent() {
return parent;
}

public void setParent(BinarySearchTreesNode<T> parent) {
this.parent = parent;
}

public BinarySearchTreesNode<T> getLeftChild() {
return leftChild;
}

public void setLeftChild(BinarySearchTreesNode<T> leftChild) {
this.leftChild = leftChild;
}

public BinarySearchTreesNode<T> getRightChild() {
return rightChild;
}

public void setRightChild(BinarySearchTreesNode<T> rightChild) {
this.rightChild = rightChild;
}

public int getKey() {
return key;

}

}

2. BST的建立

/**
* @author Administrator
*
*/
public class BinarySearchTree<T> {
private BinarySearchTreesNode<T> root;

public BinarySearchTree() {
// TODO 自动生成的构造函数存根
root = null;
}

public BinarySearchTreesNode<T> getRoot() {
return root;
}

public void setRoot(BinarySearchTreesNode<T> root) {
this.root = root;
}

public BinarySearchTree(BinarySearchTreesNode<T> binarySearchTreesNode) {
// TODO 自动生成的构造函数存根
root = binarySearchTreesNode;
}
}


二、 BST遍历

可以使用一般二叉树的遍历方法。

1. 中序遍历

/* 算法导论288页伪代码,中序遍历, */
public void inOrderTreeWalk(BinarySearchTreesNode<T> binarySearchTreesNode) {
if (binarySearchTreesNode != null) {
inOrderTreeWalk(binarySearchTreesNode.getLeftChild());
System.out.println(binarySearchTreesNode.getKey() + ":"
+ binarySearchTreesNode.getSatelliteData());
inOrderTreeWalk(binarySearchTreesNode.getRightChild());
}

}

public void inOrderTreeWalk() {
inOrderTreeWalk(root);
}

三、 BST的其他操作

1. 查找

《算法导论》P290 递归版本和循环版本

2. 最大key节点和最小key节点

《算法导论》P291

public static BinarySearchTreesNode<String> getMinimum(BinarySearchTree<String> binarySearchTree) {
BinarySearchTreesNode<String> node=binarySearchTree.getRoot();
while (node.getLeftChild()!=null) {
node=node.getLeftChild();
}
return node;
}

3. 后继和前驱

后继:节点x的后继指的是大于x.key的最小key的节点。两种情况:

1) x的右子树不为空:后继为x的右子树最小key节点。

2) x的右子树为空,x为左节点:返回x的父节点;

3) x的右子树为空,x为右节点:x的父类节点都是有节点,则最终返回null;只要x的父类节点有左节点点,则返回该父类节点的父节点即可。

伪代码:

TREE-SUCCESSOR(X)

if x.right≠NIL

return TREE-MINIMUM(x.right)

y=x.parent

while y≠NIL and x==y.right

x=y

y=y.parent

return y

*******************************************************************************

《算法导论》P293页课后题12.2-3要求写出前驱的伪代码。同理,前驱即节点x的前驱指的是小于x.key的最大key的节点。仿照上面伪代码:

TREE-PREDECESSOR(X)

if x.left≠NIL

return TREE-MAXIMUM(x.left)

y=x.parent

while y≠NIL and x==y.left

x=y

y=y.parent

return y

4. 插入

插入节点一定是叶子节点,所以不断遍历到最后符合条件的位置即可。

/*
* 算法导论294页伪代码,BinarySearchTreesNode<T>
* x从root开始遍历,只要binarySearchTreesNode.getKey()<x.getKey()则遍历左边,反之遍历右边
* 最后temp是插入位置,x=null
*/
public void insert(BinarySearchTreesNode<T> binarySearchTreesNode) {
BinarySearchTreesNode<T> temp = null;
BinarySearchTreesNode<T> x = root;
while (x != null) {
temp = x;
if (binarySearchTreesNode.getKey() < x.getKey()) {
x = x.getLeftChild();
} else {
x = x.getRightChild();
}
}
if (temp == null) {
root = binarySearchTreesNode;
} else if (binarySearchTreesNode.getKey() < temp.getKey()) {
temp.setLeftChild(binarySearchTreesNode);
} else {
temp.setRightChild(binarySearchTreesNode);
}
// System.out.println("插入完成!");
}


5. 删除

较复杂,《算法导论》P296

****************************************************************************

四、 BST转化为双向链表

参考1:/article/1491839.html

参考2:http://zhedahht.blog.163.com/blog/static/254111742007127104759245/

思路:通过递归的方式获取最左边的节点即最小的节点为头结点head,生成一个初始值为null的尾节点tail,然后递归的方式进行中序遍历,将节点tail进行移动。

java实现:

/**
* @author曹艳丰
*
*/
public classBinarySearchTreeTest {

/**
* @param args
*/
public static void main(String[] args) {
// TODO自动生成的方法存根
BinarySearchTreesNode<String>node1=newBinarySearchTreesNode<String>(6, new String("曹艳丰"));
BinarySearchTreesNode<String>node2=newBinarySearchTreesNode<String>(5, new String("习近平"));

BinarySearchTreesNode<String>node4=newBinarySearchTreesNode<String>(8, new String("王岐山"));
BinarySearchTreesNode<String>node3=newBinarySearchTreesNode<String>(7, new String("李克强"));
BinarySearchTreesNode<String>node0=newBinarySearchTreesNode<String>(4, new String("温家宝"));
node1.setLeftChild(node2);
node1.setRightChild(node4);
node2.setLeftChild(node0);
node4.setLeftChild(node3);

BinarySearchTreesNode<String>head=toLinkedList(node1);
while (head!=null) {
System.out.println(head.getKey());
head=head.getRightChild();
}
}
public staticBinarySearchTreesNode<String>toLinkedList(BinarySearchTreesNode<String> root) {
if (root==null) {
return null;
}
BinarySearchTreesNode<String>head=getLeftMostNode(root);
BinarySearchTreesNode<String>tail=null;
convert(root, tail);
return head;

}
/*将二叉树通过递归的方式转化为双向链表*/
public staticBinarySearchTreesNode<String> convert(BinarySearchTreesNode<String>root,BinarySearchTreesNode<String>tail){
if (root==null) {
return null;
}
BinarySearchTreesNode<String>leftNode=root.getLeftChild();
if (leftNode!=null) {
tail=convert(leftNode, tail);
}
/*tail是链表末尾,加入下一个节点后tail后移*/
if (tail!=null) {
tail.setRightChild(root);
}
tail=root;

BinarySearchTreesNode<String>rightNode=root.getRightChild();
if (rightNode!=null) {
tail=convert(rightNode, tail);
}
return tail;
}
public staticBinarySearchTreesNode<String>getLeftMostNode(BinarySearchTreesNode<String> root) {
BinarySearchTreesNode<String>temp=root;
while (temp.getLeftChild()!=null) {
temp=temp.getLeftChild();
}
return temp;
}
}

****************************************************************************

【一道面试题】:BST如何高效地找到中位数。

参考:/article/8206122.html

答案:BST转化为双向链表,双向链表是排好序的,两个指针一个速度是另一个两倍,快的移到最后,慢的即中位数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐