代码改变世界

Java实现二叉搜索树

2022-11-22 17:06  杭伟  阅读(95)  评论(0编辑  收藏  举报

将链表进行改造,即可构造一棵二叉树。

本文用java实现一颗二叉搜索树,实现二叉树的新增,删除,查找等功能。并测试新增和查找的时间复杂度。

节点类与链表节点相似,将链表的前后节点定义逻辑改为左右(孩子)节点:

/**
 * 二叉搜索树节点
 */
public class Node
{
    private int data;//数据域
    private Node left;//左节点(左孩子)
    private Node right;//右节点(右孩子)

    public int getData() {
        return data;
    }
    public void setData(int data) {
        this.data = data;
    }
    public Node getLeft() {
        return left;
    }
    public void setLeft(Node left) {
        this.left = left;
    }
    public Node getRight() {
        return right;
    }
    public void setRight(Node right) {
        this.right = right;
    }

    //构造函数
    public Node(int data, Node left, Node right){
        this.data = data;
        this.left = left;
        this.right = right;
    }
    public Node(int data){
        this(data,null,null);
    }
    public Node(){
        this(0,null,null);
    }

}

二叉搜索树的实现:

 1 /**
 2  * 二叉搜索树
 3  * Author:hangwei
 4  * Date:2022/11
 5  */
 6 public class SearchTree {
 7     private Node root;
 8     public Node getRoot() {
 9         return root;
10     }
11     public void setRoot(Node root) {
12         this.root = root;
13     }
14 
15     //查找树中是否存在某个值
16     public Node search(Node root,int val){
17         int nums = 0;
18         while (root != null && root.getData() != val){
19             if(val < root.getData())//位于左子树
20                 root = root.getLeft();//缩小范围
21             else
22                 root = root.getRight();
23             nums++;
24         }
25         System.out.println("本次查找执行了:"+nums+"次");
26         return root;
27     }
28 
29     int addCount = 0;
30     //给树新增节点
31     public void Add(Node root,int val){
32         if(val == 30)
33             addCount++;
34         if(root == null) {
35             setRoot(new Node(val));
36         }
37         else {
38             if(val < root.getData()){
39                 if(root.getLeft() == null)//左子树为空新增
40                     root.setLeft(new Node(val));
41                 else
42                     Add(root.getLeft(),val);//缩小子树范围并递归
43             }
44             else {
45                 if(root.getRight() == null)//右子树为空新增
46                     root.setRight(new Node(val));
47                 else
48                     Add(root.getRight(), val);
49             }
50             //验证插入的时间复杂度
51             if(root.getRight()!=null && root.getRight().getData() == 30)
52                 System.out.println("本次新增节点30执行了:"+addCount+" 次");
53         }
54 
55     }
56     public Node delete(Node root,int val){
57         if(root == null)
58             return root;
59         if(root.getData() == val){//找到节点
60             if(root.getLeft() == null && root.getRight() ==null){//1,左右子节点为空则直接返回空
61                 return null;
62             } else if (root.getLeft() == null) {//2,左孩子节点为空则返回右孩子节点
63                 return root.getRight();
64             } else if (root.getRight() == null) {//3,右孩子节点为空则返回左孩子节点
65                 return root.getLeft();
66             }
67             else {//4,左右孩子节点都不为空
68                 Node cur = root.getRight();
69                 while (cur.getLeft() !=null)//如果右节点有孩子节点且左孩子不为空
70                     cur = cur.getLeft();//找到右节点的最小左孩子
71                 cur.setLeft(root.getLeft());//因为被删除目标节点的右子树始终比左子树大,所以找到右子树的最小左孩子,并设置最小左孩子的左子树为目标节点的左子树
72                 return root.getRight();
73             }
74         }
75         else if(val < root.getData())//处理左子树
76             root.setLeft(delete(root.getLeft(),val));
77         else//处理右子树
78             root.setRight(delete(root.getRight(),val));
79         return root;
80     }
81 }
View Code

测试类:

import java.util.*;

public class Main {
    public static void main(String[] args) {
        /**
         * 假设有一颗二叉搜索树,总结点树是n,高度是h,根节点的高度是1,假设也是满二叉树,
         * 则n与h的关系:n=2^h - 1;(极端情况n=h暂不考虑退化到链表的情况)
         * 即:h=log2^(n+1)
         */
        //二叉搜索树测试
        SearchTree st = new SearchTree();
        //插入节点&验证插入的时间复杂度
        st.Add(null,25);
        st.Add(st.getRoot(),18);
        st.Add(st.getRoot(),16);
        st.Add(st.getRoot(),19);
        st.Add(st.getRoot(),29);
        st.Add(st.getRoot(),27);
        st.Add(st.getRoot(),30);

        //输出树
        System.out.println(Arrays.toString(levelOrder(st.getRoot())));
        //查找
        System.out.println(st.search(st.getRoot(),27).getData());
        System.out.println(st.search(st.getRoot(),30).getData());
        System.out.println(st.search(st.getRoot(),31));
        //验证查找的时间复杂度

        //删除节点
        st.delete(st.getRoot(),30);
        //再次输出树
        System.out.println(Arrays.toString(levelOrder(st.getRoot())));
        //删除节点
        st.delete(st.getRoot(),18);
        //再次输出树
        System.out.println(Arrays.toString(levelOrder(st.getRoot())));
    }


    /**
     * 层序遍历
     * @param root
     * @return
     */
    public static int[] levelOrder(Node root) {
        if(root == null){
            return new int[0];
        }

        Queue<Node> queue = new LinkedList<Node>();
        queue.add(root);
        ArrayList<Integer> arr = new ArrayList<>();
        while( !queue.isEmpty() ){
            Node temp = queue.poll();
            arr.add(temp.getData());
            if(temp.getLeft() != null){
                queue.add(temp.getLeft());
            }
            if(temp.getRight() != null){
                queue.add(temp.getRight());
            }
        }
        int[] res = new int[arr.size()];
        for(int i = 0;i < arr.size();i++){
            res[i] = arr.get(i);
        }

        return res;

    }

}

执行结果:

 

 

*重点:

1,双向链表即可改造成二叉树;

2,二叉搜索树定义:左子树小于根节点,右子树大于根节点,左子树和右子树的子树一样符合这个定义;

3,新增,查找,删除方法中无处不在的递归思路;

4,层序遍历和时间复杂度验证。