关于BST树的一些基本概念上一篇博客已经说过了,今天对bst树做了增,查、删以及查找最小值的操作,使用java代码实现。从代码中对这个bst有了更深的理解。
bst概念重申一下
来自百度百科:二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的
左子树不空
,则左子树上所有结点
的值均小于
它的根结点的值
; 若它的右子树不空
,则右子树上所有结点
的值均大于
它的根结点的值
; 它的左、右子树也分别为二叉排序树。
直接上代码
1.创建一个树类
public class TreeNode {
int val;
TreeNode leftNode;
TreeNode rightNode;
public TreeNode(int x) {
val = x;
}
}
测试开始,代码中均使用的是递归,不用递归的话用while循环也可
public class BSTDemo {
//数组生成 bst树
public TreeNode BSTInsert(int[] arr) {
TreeNode treeNode = null;
for(int i=0;i<arr.length;i++){
treeNode = insert(treeNode, arr[i]);
}
return treeNode;
}
//插入
public TreeNode insert(TreeNode node,int a){
if(node != null){
if(node.val < a){
node.rightNode = insert(node.rightNode, a);
}else if(node.val > a){
node.leftNode = insert(node.leftNode, a);
}else if(node.val == a){
node.val = a;
}
}else {
return new TreeNode(a);
}
return node;
}
/**
* 查找 这里是我刚开始搞错了,因为我以为二叉树搜索树会出现相同的值,自己试验以及百度之后,
* 发现不会存在相同的值。所以这下面有用到了BFS盲目搜索算法(详情看我另外一篇博客),
* 遍历整个二叉树,把符合条件的节点添加到list中。看网上说这又叫层次遍历。
*
* 当知道BST不会出现重复值得特性后,可直接再if(poll.val == a) list.add(poll);这句后return poll; 以下代码懒得改了
*
* 查找个插入很相似,还有其他方式,也可用简单的代码实现,这里这就不详细说了
*/
public void find(TreeNode node , int a,List<TreeNode> list){
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(node);
while(!queue.isEmpty()){
int size = queue.size();
for(int i=0;i<size;i++){
TreeNode poll = queue.poll();
if(poll.val == a) list.add(poll);
if(poll.leftNode != null){
queue.offer(poll.leftNode);
}
if(poll.rightNode != null){
queue.offer(poll.rightNode);
}
}
}
}
/**
* 普通查找节点
* @param node
* @param a
* @return
*/
public TreeNode find2(TreeNode node,int a){
if(node != null){
if(node.val < a) node = find2(node.rightNode, a) ;
if(node.val > a) node = find2(node.leftNode, a) ;
}else {
return null;
}
return node;
}
/**
* 查找最小值,因为最小值是肯定没有右子树的
* 查找最大值同理
* @param node
* @return
*/
public TreeNode min(TreeNode node) {
if(node == null) return null;
while(node.leftNode !=null ){
node = node.leftNode;
}
return node;
}
/**
* 删除某个节点,这里分为三种情况
* 1.该节点没有左右子树,删除节点之后不影响树结构
* 2.该子节点只有左子树PL或右子树PR,只需要让PL或者RL成为该节点的父节点的RL或者PL即可,不改变搜索树的特性
* 3.若该结点P的左子树和右子树均不空。在删去p之后,为保持其它元素之间的相对位置不变,可按中序遍历保持有序进行调整,
* 即先用P节点右子树的最小数据替换该结点,然后递归地删除那个最小数据的结点(这个最小数据结点一定是没有左孩子的)
* @param treeNode
* @param a
*/
public TreeNode delete(TreeNode node, int a) {
if (node != null) {
// 这下面两步是为了查找到a的节点
if (node.val < a) {
node.rightNode = delete(node.rightNode, a);
} else if (node.val > a) {
node.leftNode = delete(node.leftNode, a);
} else if (node.val == a) {
if (node.leftNode == null && node.rightNode == null && node.val == a) {
return node = null;
}else if (node.leftNode != null && node.rightNode == null) {
return node.leftNode;
}else if (node.leftNode == null && node.rightNode != null) {
return node.rightNode;
}else if (node.leftNode != null && node.rightNode != null) {
// 找出右子树中的最小值
TreeNode node2 = min(node.rightNode);
// 将最小值赋予node
node.val = node2.val;
// 删除node2节点
node.rightNode = delete(node.rightNode, node2.val);
return node;
}
}
} else {
return node;
}
return node;
}
public static void main(String[] args) {
int[] a = {32,18,40,9,28,65,12,12,29,56,87};
// int[] a = {32,18,40,9,28,65,12,12,29,56,87,1,2,3,4};
BSTDemo demo = new BSTDemo();
TreeNode bstInsert = demo.BSTInsert(a);
// System.out.println(demo);
List<TreeNode> list = new ArrayList<>();
demo.find(bstInsert,28, list);
for(TreeNode tn : list){
System.out.println(tn);
System.out.println(tn.val);
}
TreeNode find2 = demo.find2(bstInsert,0);
if(find2 == null){
System.out.println("没有找到");
}else {
System.out.println(find2.val);
}
System.out.println(demo.min(bstInsert).val);
TreeNode delete = demo.delete(bstInsert, 18);
System.out.println(delete);
}
}
下面上图
这是第一个数组生成的bst树
删除18节点过程
假设18节点为P
首先遍历节点P的右子树,得到最小的值为28,此时将节点P的val改为28,然后删除P的右子树,让右子树指向29
删除18节点后
有不对的地方望大家指正