二叉搜索树
左子树的节点值小于根节点的值,右子树的节点值大于根节点的值,且没有重复节点。
二叉搜索树插入数据(5、11、22)举例(插入任何数据都能够在叶子节点上完成插入):
public class TestBinaryTree {
//静态节点
static class Node{
public int data;
public Node left;
public Node right;
public Node(int data) {
this.data = data;
this.left = null;
this.right = null;
}
}
public Node root = null;
//插入(其实就是找叶子节点,且插入位置不在叶子节点左边就是在叶子节点右边)
public void insert(int key) {
Node node = new Node(key);
Node cur = root;
Node parent =null;
if(root==null){
root=node;
return;
}
//找叶子节点(parent)(正确的插入节点)
while(cur!=null){
if(cur.data>node.data){
parent=cur;
cur=cur.left;
}else if(cur.data<node.data){
parent=cur;
cur=cur.right;
}else{
//cur.data=node.data的情况需要排除掉
return;
}
}
//开始插入
//parent.data>node.data时,在左边插入
if(parent.data>node.data){
parent.left=node;
}else{
// parent.data<node.data时,在右边插入
parent.right=node;
}
}
//查找
public Node search(int key){
Node cur = root;
while(cur!=null){
if(key<cur.data){
cur=cur.left;
}else if(key==cur.data){
return cur;
} else{
cur=cur.right;
}
}
return null;
}
//前序遍历
public void preOrder(Node root){
if(root!=null){
System.out.print(root.data+" ");
preOrder(root.left);
preOrder(root.right);
}
}
//中序遍历
public void inOrder(Node root){
if(root!=null){
inOrder(root.left);
System.out.print(root.data+" ");
inOrder(root.right);
}
}
二叉搜索树删除数据
(1)首先要找到要删除的节点cur及其父节点parent
//删除关键字为key的节点
public void remove(int key) {
Node cur = root;
Node parent = null;
while (cur != null) {
if(cur.data == key) {
//找到要删除的节点,及其父节点,然后进行删除
removeNode(parent,cur);
return;
}else if(cur.data < key) {
parent = cur;
cur = cur.right;
}else {
parent = cur;
cur = cur.left;
}
}
}
(2)删除数据分三种情况:
1)cur.left==null
cur==root,则root=cur.right;
cur!=root,若cur在父节点的左边,则parent.left=cur.right;
cur!=root,若cur在父节点的右边,则paretn.right=cur.right;
cur.left==null
且cur在parent的左边的情况:
2)cur.right==null
cur==root,则root=cur.left;
cur!=root,若cur在父节点的左边,则parent.left=cur.left;
cur!=root,若cur在父节点的右边,则paretn.right=cur.left;
cur.right==null
且cur在parent的右边:
3)cur.right!=null&&cur.left!=null
要用替换法解决,即选择左树值最大的X节点进行替换,或选择右树值最小的X节点进行替换,最后需要删除X节点(其实cur节点并未被删除,只是值被改变)。
public void removeNode(Node parent,Node cur){
if(cur.left == null) {
if(cur == root) {
root=cur.right;
}else if(cur == parent.left){
parent.left=cur.right;
}else { //cur == parent.right
parent.right = cur.right;
}
}else if(cur.right == null) {
if(cur == root) {
root=cur.left;
}else if(cur == parent.left){
parent.left=cur.left;
}else { //cur == parent.right
parent.right = cur.left;
}
}else {
Node targetParent = cur;
//记录真正要删除节点的父亲节点
//(即左树最大值或右树最小值的父节点)
//在右边找最小值
Node target = cur.right;
while (target.left != null) {
targetParent = target;
target = target.left;
}
cur.data = target.data;
//target的左肯定是空的
if(target == targetParent.left) {
//target.right可能为空,也可能不为空
targetParent.left = target.right;
}else {
targetParent.right = target.right;
}
}
}
小记:
- 二叉搜索树的深度代表了二叉搜索树的时间复杂度,节点越深,则比较次数越多。
- 最优情况下,二叉搜索树为完全二叉树,其平均比较次数为log2N.
- 最坏情况下,二叉搜索树为单支树,其平均比较次数为N/2.
- 同样的一组数据,组成二叉搜索树的次序不同,会造成其节点深度不同。