二分搜索树的相关内容
二分搜索树-------1_qq_15255121的专栏-CSDN博客
二分搜索树-------2 查询与遍历_qq_15255121的专栏-CSDN博客
二分搜索树-------3 删除元素_qq_15255121的专栏-CSDN博客
下面是具体的代码
package com.yuanxuzhen.map;
import com.yuanxuzhen.tree.YuanBST;
public class YuanBstMap <K extends Comparable<K>, V> implements Map<K, V>{
private class Node{
Node left;
Node right;
K key;
V value;
public Node(K key, V value) {
this.key = key;
this.value = value;
this.left = null;
this.right = null;
}
}
private Node root;
private int size;
public YuanBstMap() {
this.root = null;
this.size = 0;
}
@Override
public void add(K key, V value) {
root = add(root, key, value);
}
private Node add(Node node, K key, V value){
//null可以看做是二叉树
if(node == null){
++size;
return new Node(key, value);
}
if(key.compareTo(node.key) < 0){
//如果插入的元素小于节点值,且左子树不为空,递归插入左子树
node.left = add(node.left, key, value);
}else if(key.compareTo(node.key) > 0){
//如果插入的元素大于节点值,且右子树不为空,递归插入右子树
node.right = add(node.right, key, value);
}else{
node.value = value;
}
return node;
}
@Override
public V remove(K key) {
Node node = getNote(root, key);
if(node != null){
root = remove(root, key);
return node.value;
}
return null;
}
@Override
public boolean contains(K key) {
return getNote(root, key) != null;
}
@Override
public V get(K key) {
Node node = getNote(root, key);
if(node != null){
return node.value;
}
return null;
}
private Node getNote(Node node, K key){
if(node == null){
return null;
}
if(key.compareTo(node.key) < 0){
return getNote(node.left, key);
}else if(key.compareTo(node.key) > 0){
return getNote(node.right, key);
}else {
return node;
}
}
@Override
public void set(K key, V value) {
Node node = getNote(root, key);
if(node != null){
node.value = value;
}
}
@Override
public int getSize() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
/**
* 二分搜索树的特点,每个节点最多只有两个子节点,左节点 < 根节点 < 右节点
* 所以最左侧的节点就是最小值
* @return
*/
public V minmum(){
if(size == 0){
throw new IllegalArgumentException("树为空");
}
return minmum(root).value;
}
private Node minmum(Node node){
if(node.left == null){
return node;
}
return minmum(node.left);
}
/**
* 二分搜索树的特点,每个节点最多只有两个子节点,左节点 < 根节点 < 右节点
* 所以最右侧的节点就是最大值
* @return
*/
public V maxMum(){
if(size == 0){
throw new IllegalArgumentException("树为空");
}
return minmum(root).value;
}
private Node maxMum(Node node){
if(node.right == null){
return node;
}
return maxMum(node.right);
}
/**
* 删除最小值,最小值所在的节点,左子树为null,右子树可能不为null也可能是null
* 如果右子树为null,那么直接删除当前节点即可,即把父节点的左子树置位null即可。
* 如果右子树不为null,那么删除当前节点,同时把当前节点的右子树置为父节点的左子树
* @return
*/
public V removeMin(){
V entry = minmum();
root = removeMin(root);
return entry;
}
private Node removeMin(Node node){
if(node.left == null){
//这里把null当做了特殊的节点,不管右节点是否为null,都要返回右节点,做为父节点的左子树
Node rightNode = node.right;
rightNode.right = null;
size--;
return rightNode;
}
//继续寻找最小的节点
node.left = removeMin(node.left);
return node;
}
/**
* 删除最大值,最大值所在的节点,一直向右找,右子树为null,左子树可能不为null也可能是null
* 如果左子树为null,那么直接删除当前节点即可,即把父节点的右子树置位null即可。
* 如果左子树不为null,那么删除当前节点,同时把当前节点的左子树置为父节点的右子树
* @return
*/
public V removeMax(){
V entry = maxMum();
root = removeMax(root);
return entry;
}
private Node removeMax(Node node){
if(node.right == null){
//这里把null当做了特殊的节点,不管左节点是否为null,都要返回左节点,做为父节点的右子树
Node leftNode = node.left;
leftNode.right = null;
size--;
return leftNode;
}
//继续寻找最大的节点
node.right = removeMax(node.right);
return node;
}
private Node remove(Node node, K key){
if(key.compareTo(node.key) < 0){
node.left = remove(node.left, key);
return node;
}else if(key.compareTo(node.key) > 0){
node.right = remove(node.right, key);
return node;
}else{
if(node.left == null){
Node rightNote = node.right;
node.right = null;
return rightNote;
}else if(node.right == null){
Node leftNode = node.left;
node.left = null;
return leftNode;
}else{
/**
* 删除的节点左右子树都不为空,这里有两种处理方式,
* 用左子树的最大值或者右子树的最小值代替。都可以满足做子树<根节点<右子树
*/
Node replaceNode = null;
//使用左子树的最大值
// replaceNode = maxMum(node.left);
// node.left = removeMax(node.left); //这里二叉树少了一个元素
// size++; //少了的元素我们还要使用所以这里要加回来
// //替换节点替换当前节点
//使用右子树的最小值
replaceNode = minmum(node.right);
node.right = removeMin(node.right); //这里二叉树少了一个元素
size++; //少了的元素我们还要使用所以这里要加回来
//替换节点替换当前节点
replaceNode.left = node.left;
replaceNode.right = node.right;
node.left = node.right = null; //删除了当前节点
size--;
return replaceNode;
}
}
}
}