day12二叉搜索树
概述
- 树节点增加key属性,用来比较谁大谁小,key不可以重复
- 对于任意一个树节点,它的key比左子树的key都大,同时也比右子树的key都小
二叉搜索树节点类
public class BSTTree {
/**
* 二叉搜索树节点类
*/
static class BSTNode {
//key属性
int key;
//value可以是任意内容
Object value;
//left是左节点
BSTNode left;
//right是右节点
BSTNode right;
public BSTNode(int key) {
this.key = key;
}
public BSTNode(int key, Object value, BSTNode left, BSTNode right) {
this.key = key;
this.value = value;
this.left = left;
this.right = right;
}
public BSTNode(int key, Object value) {
this.key = key;
this.value = value;
}
}
}
查找关键字时对应的值
使用递归
/**
* 查找关键字对应的值
* @param key
* @return
*/
public Object get(int key){
return doGet(root,key);
}
/**
* 创建一个方法使用递归去查找关键字对应的值
* @param node
* @param key
* @return
*/
private Object doGet(BSTNode node,int key){
//没找到的情况
if(node == null){
return null;
}
//判断如果查找的key比当前的key小的话,去左边继续找
if(key< node.key){
return doGet(node.left,key);
}
//如果查找的key比当前的key大的话,去右边继续找
else if(key > node.key){
return doGet(node.right,key);
}
//否则找到的话就返回当前的值
else{
return node.value;
}
}
测试
public class Test {
public static BSTTree createTree(){
/**
* 4
* / \
* 2 6
* / \ / \
* 1 3 5 7
*/
BSTTree.BSTNode n1 = new BSTTree.BSTNode(1, "张无忌");
BSTTree.BSTNode n3 = new BSTTree.BSTNode(3, "宋青书");
BSTTree.BSTNode n2 = new BSTTree.BSTNode(2, "周芷若",n1,n3);
BSTTree.BSTNode n5 = new BSTTree.BSTNode(5, "说不得");
BSTTree.BSTNode n7 = new BSTTree.BSTNode(7, "引力");
BSTTree.BSTNode n6 = new BSTTree.BSTNode(6, "赵敏",n5,n7);
BSTTree.BSTNode root = new BSTTree.BSTNode(4, "小昭",n2,n6);
BSTTree tree = new BSTTree();
tree.root = root;
return tree;
}
public static void main(String[] args) {
BSTTree tree = createTree();
Object o = tree.get(1);
System.out.println(o);
}
}
不使用递归
/**
* 使用非递归的方式查找关键字对应的值
* @pajian'zy
* @return
*/
public Object get1(int key){
//让根节点赋值为node
BSTNode node = this.root;
//循环遍历,直到node不为空
while (node != null){
//判断如果查找的key比当前节点的key
if(key < node.key){
//将当前的node节点变为左节点
node = node.left;
}
//判断如果查找的key比当前节点的key大的话
else if(key > node.key){
//将当前的node节点变为右节点
node = node.right;
}else{
//否则返回node.value值
return node.value;
}
}
return null;
}
测试
public class Test {
public static BSTTree createTree(){
/**
* 4
* / \
* 2 6
* / \ / \
* 1 3 5 7
*/
BSTTree.BSTNode n1 = new BSTTree.BSTNode(1, "张无忌");
BSTTree.BSTNode n3 = new BSTTree.BSTNode(3, "宋青书");
BSTTree.BSTNode n2 = new BSTTree.BSTNode(2, "周芷若",n1,n3);
BSTTree.BSTNode n5 = new BSTTree.BSTNode(5, "说不得");
BSTTree.BSTNode n7 = new BSTTree.BSTNode(7, "引力");
BSTTree.BSTNode n6 = new BSTTree.BSTNode(6, "赵敏",n5,n7);
BSTTree.BSTNode root = new BSTTree.BSTNode(4, "小昭",n2,n6);
BSTTree tree = new BSTTree();
tree.root = root;
return tree;
}
public static void main(String[] args) {
BSTTree tree = createTree();
Object o = tree.get1(2);
System.out.println(o);
}
}
泛型key
public class BSTTree1<T extends Comparable<T> ,V> {
/**
* 二叉搜索树节点类
*/
static class BSTNode<T,V> {
T key;
V value;
BSTNode left;
BSTNode right;
public BSTNode(T key) {
this.key = key;
}
public BSTNode(T key, V value, BSTNode<T,V> left, BSTNode<T,V> right) {
this.key = key;
this.value = value;
this.left = left;
this.right = right;
}
public BSTNode(T key, V value) {
this.key = key;
this.value = value;
}
}
BSTNode<T,V> root;
public Object get(T key){
BSTNode<T,V> p = this.root;
while ( p !=null){
//key p.key
/**
* -1 key < p.key
* 0 key == p.key
* 1 key > p.key
*/
int result = key.compareTo(p.key);
if(result<0){
p = p.left;
}else if(result>0){
p = p.right;
}else{
return p.value;
}
}
return null;
}
}
寻找最小值对应的关键字
递归
/**
* 使用递归的方式查找最小关键字对应的值
* @return
*/
public Object min1(BSTNode node){
//当传过来的节点为null值的时候返回null
if(node == null){
return null;
}
//判断如果当前节点的最左侧为null的话,说明已经找到最小值了,可以直接返回
if(node.left == null){
return node.value;
}
//否则的话,一直递归直到找到当前节点的左侧为null
return min1(node.left);
}
非递归
/**
* 查找最小关键字对应值
* @return
*/
public Object min(){
//curr代表着当前节点
BSTNode curr = this.root;
//判断如果curr为null的话此时的最小节点压根就不存在
if(curr == null){
return null;
}
//一直遍历到curr.left不为null
while (curr.left != null){
curr = curr.left;
}
//最终返回当前节点的value
return curr.value;
}
寻找最大值对应的关键字
递归
/**
* 查找最大关键字对应的值
* @return
*/
public Object max(BSTNode node){
if(node == null){
return null;
}
if(node.right == null){
return node.value;
}
return max(node.right);
}
非递归
/**
* 查找最大关键字对应的值
* @return
*/
public Object max1(){
BSTNode curr = this.root;
if(curr == null){
return null;
}
while (curr.right != null){
curr = curr.right;
}
return curr.value;
}
存储关键字和对应值
/**
* 存储关键字和对应值
* @param key
* @param value
*/
public void put(int key,Object value){
//1.key 有的话 更新操作
BSTNode node = this.root;
BSTNode parent = null; //没有找到的时候的最后一个节点
while (node != null){
//更新parent节点
parent = node;
if(key < node.key){
node = node.left;
}else if(key > node.key){
node = node.right;
}else{
//找到了,更新最新节点的值
node.value = value;
return;
}
}
//parent 父节点
//如果找到的父节点为空的话,此时添加的节点就应该是父节点
if(parent == null){
root = new BSTNode(key,value);
}
//2.key 没有的话 新增
//new BSTNode(key,value);
//判断新的key和父亲的key哪个值更大,如果父亲的大的话就给左边添加
if(key < parent.key){
parent.left = new BSTNode(key,value);
}
//如果右侧的key比父亲的key大的话,就给右面添加
else if(key > parent.key){
parent.right = new BSTNode(key,value);
}
}
前任和后任
后任
/**
* 寻找一个节点的最小值
* @param node
* @return
*/
private Object min2(BSTNode node) {
BSTNode curr = node;
if(curr == null){
return null;
}
while (curr.left != null){
curr = curr.left;
}
return curr.value;
}
/**
* 查找关键字的后任值
* @param key
* @return
*/
public Object successon(int key){
BSTNode p = root;
BSTNode ancestorFromRight = null;//自左而来的祖先
while (p != null){
if(key < p.key){
//这一行代码代表的就是找左边,所以可以确定是从右边来的
ancestorFromRight = p;
p = p.left;
}else if(p.key < key){
p= p.right;
}else{
break;
}
}
//没找到节点
if(p == null){
return null;
}
/**
* 情况1:节点有右子树,此时前任就是左子树的最小值
* 情况2:节点没有右子树,若离它最近的,自右而来的祖先就是后任
*/
//情况1
if(p.right != null){
return min2(p.left);
}
//情况2
return ancestorFromRight != null ?ancestorFromRight.value:null;
}
前任
/**
* 寻找任意一个节点的最大值
* @param node
* @return
*/
private Object max2(BSTNode node){
if(node == null){
return null;
}
BSTNode p = node;
while (p.right != null){
p = p.right;
}
return p.value;
}
/**
* 查找关键字的前任值
* @param key
* @return
*/
public Object predecessor(int key){
BSTNode p = root;
BSTNode ancestorFromLeft = null;//自左而来的祖先
while (p != null){
if(key < p.key){
p = p.left;
}else if(p.key < key){
//这一行代码代表的就是找右边,所以可以确定是从左边来的
ancestorFromLeft = p;
p= p.right;
}else{
break;
}
}
//没找到节点
if(p == null){
return null;
}
/**
* 情况1:节点有左子树,此时前任就是左子树的最大值
* 情况2:节点没有左子树,若离它最近的,自左而来的祖先就是前任
*/
//情况1
if(p.left != null){
return max(p.left);
}
//情况2
return ancestorFromLeft != null ?ancestorFromLeft.value:null;
}
删除
/**
* 根据关键字删除对应值
* @param key
* @return
*/
public Object delete(int key){
BSTNode p = root;
BSTNode parent = null;//记录父节点
while ( p!= null){
if(key < p.key){
parent = p;
p = p.left;
}else if(p.key < key){
parent = p;
p = p.right;
}else{
break;
}
}
if(p == null){
return null;
}
/**
* 删除节点: 1.删除节点没有左孩子,将右孩子托孤给parent
* 2.删除节点没有右孩子,将左孩子托孤给parent
*/
//删除操作
if(p.left == null){
//情况1
shift(parent,p,p.right);
}else if(p.right == null){
//情况2
shift(parent,p,p.left);
}else{
//情况四
//1.找到被删除节点的后继节点
BSTNode s = p.right;
BSTNode sParent = p;//后继父亲
while (s.left != null){
sParent = s;
s = s.left;
}
//后继节点即为s
//如何判断需不需要处理后事节点
//如果后继节点的父亲就是删除的节点的话,就代表着不需要处理后事节点,否则就需要处理后事节点
//2.处理后继的后事
if(sParent != p){
//删除和后继不相邻,处理后继的节点
shift(sParent,s,s.right);//不可能有左孩子的
s.right = p.right;
}
//3.后继取代被删除节点
shift(parent,p,s);//此时的s就是后继节点,此时的p就是删除节点,parent就是删除节点的父节点
s.left = p.left;
}
return p.value;
}
/**
* 实现托孤方法
* parent被删除的节点
* deleted被删除的节点
* child被顶上去的节点
j */
private void shift(BSTNode parent,BSTNode deleted,BSTNode child){
//判断如果当前节点的父节点是空的话,此时的根节点就应该变为child
if(parent == null){
root = child;
}
//判断如果删除的节点是父节点的左节点的话,那么父元素左节点就是子节点
else if(deleted == parent.left){
parent.left = child;
}
//判断如果删除的节点是父节点的右节点的话,那么父元素右节点就是子节点
else{
parent.right = child;
}
}
}
return p.value;
}
/**
* 实现托孤方法
* parent被删除的节点
* deleted被删除的节点
* child被顶上去的节点
j */
private void shift(BSTNode parent,BSTNode deleted,BSTNode child){
//判断如果当前节点的父节点是空的话,此时的根节点就应该变为child
if(parent == null){
root = child;
}
//判断如果删除的节点是父节点的左节点的话,那么父元素左节点就是子节点
else if(deleted == parent.left){
parent.left = child;
}
//判断如果删除的节点是父节点的右节点的话,那么父元素右节点就是子节点
else{
parent.right = child;
}
}