二叉搜索树(实现增删查,前中后层次遍历、获取深度和结点数量)

俺一直觉得二叉树是一个天然适合用递归处理的结构,只能从顶开始,面前只有两条路,不断将问题细化直到最底,然后再倒回去选择另一种路。
而二叉搜索树的结构就是在二叉树的基础上,多了一个规则,某结点的左子树的结点总是小于它,右子树的结点总是大于它,且结点唯一 [1]
写一个二叉搜索树的结构,最核心的地方就是查找,如果会查找了,俺感觉其他都差不多。

二叉树

static class TreeNode<T extends Comparable<? super T>> {
        T val;
        TreeNode<T> left;
        TreeNode<T> right;

        TreeNode(T t){
            val = t;
        }
    }

查找

根据那条规则[1],我们知道,如果要找一个值在树中是否存在,小了就找左树,大了就找右树,而且不用回溯的,找不到就是找不到,倒回去也找不到。


	private TreeNode serch(T val){
        if(isEmploy()||val==root.val){
        //Empty,emmm拼错了,懒得改也
            return root;
        }
        return serch(root,val);
    }

    private TreeNode  serch(TreeNode<T> t,T val){
        if(t==null){
            return null;
        }
        if(t.val.compareTo(val)==0){
            return t;
        }

        if(t.val.compareTo(val)>0){
            return serch(t.left,val);
        }else {
            return serch(t.right,val);
        }
    }

插入

跟查找类似,如果存在于树中,就不用插了,如果不存在,那就找到合适的地方,找到属于它的那个空结点。

public void insert(T val){
        if(exist(val)){//如果存在于子树
            return;
        }else if(isEmploy()){
            root = new TreeNode<>(val);
        }else{
            insert(val,root);
        }
        size++;
    }
private void insert(T val,TreeNode<T> root){
        if(root.val.compareTo(val)<0){
            if(root.right==null){
                root.right = new TreeNode<>(val);
                return;
            }
            insert(val,root.right);
        }else {
            if(root.left==null){
                root.left = new TreeNode<>(val);
                return;
            }
            insert(val,root.left);
        }
    }

删除

注意删除和前两个操作略有差异,由于删除后我们需要调整结点。有三种情况(当然也阔能树中根本没那个结点)

  1. 该结点只有左子树:用左子树的首个结点替换它
  2. 只有右子树:用右子树的首个结点替换它
  3. 都有:这种就有点难顶了,这里我们采用的方式是找一个肯定会大于它左子树所有值又小于它右子树所有值的结点来替换它。有两种选择:1.左子树的最右结点 2.右子树的最左结点。这里我们采用的第二种
    不过注意这里它涉及到回溯了(当然如果能保存它的父节点的话倒也不用回溯),因为需要将更改后的子树与其父节点连接起来。
public void delete(T val){
        root = delete(root,val);
        size--;
    }
    private TreeNode delete(TreeNode<T> root, T val) {
        if(root==null){
            return null;
        }
        if(root.val.compareTo(val)>0){
            root.left = delete(root.left,val);
        }else if(root.val.compareTo(val)<0){
            root.right = delete(root.right,val);
        }else{
            if(root.left!=null||root.right!=null){
                TreeNode<T> temp = root.left;
                //找到最右结点
                while(temp.right!=null){
                    temp = temp.right;
                }
                root.val = temp.val;
                //为了将树连起来,如果有指针的话倒是阔以直接赋值为null
                root.left = linked(root.left);
            }else if(root.left!=null){
                root = root.left;
            }else if(root.right!=null){
                root = root.right;
            }else {
                root = null;
            }
        }
        return root;
    }
    private TreeNode<T> linked(TreeNode treeNode){
        if(treeNode.right==null){
            return treeNode.left;
        }
        treeNode.right = linked(treeNode.right);
        return treeNode;
    }

遍历

有四种遍历方式:

	private enum ModeEnum {
        pre("pre"),mid("mid"),after("after"),levelOrder("levelOrder");
        private String mode;
        ModeEnum(String mode){
            this.mode = mode;
        }
    }
    public List<T> toList(String s){
        if(isEmploy()){
            return null;
        }
        ModeEnum mode = ModeEnum.valueOf(s);
        List<T> list = new ArrayList<>();
        switch (mode){
            case mid:
                mid(root,list);
                break;
            case pre:
                pre(root,list);
                break;
            case after:
                after(root,list);
                break;
            case levelOrder:
                levelOrder(root,list);
                break;
            default:
                mid(root,list);
        }
        return list;
    }

前中后遍历很简单,用递归的方式写的话,都是基于深搜+回溯的思想,每个结点都是父节点 ,不过它的儿子阔能是null而已。

private void after(TreeNode<T> root, List<T> list) {
        if(root==null){
            return;
        }
        after(root.left,list);
        after(root.right,list);
        list.add(root.val);
    }

    private void pre(TreeNode<T> root, List<T> list) {
        if(root==null){
            return;
        }
        list.add(root.val);
        pre(root.left,list);
        pre(root.right,list);
    }


    private void mid(TreeNode<T> node,List<T> list){
        if(node==null){
            return;
        }
        mid(node.left,list);
        list.add(node.val);
        mid(node.right,list);
    }

层次遍历,比较自然的想法就是广度优先了。要尊老嘛(不是),父辈的儿子结点肯定优先于子辈的儿子,要实现这种操作使用队列呀。

private void levelOrder(TreeNode<T> root, List<T> list) {
        Queue<TreeNode<T>> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            TreeNode<T> t = queue.poll();
            if(t.left!=null){
                queue.offer(t.left);
            }
            if(t.right!=null){
                queue.offer(t.right);
            }
            list.add(t.val);
        }
    }

最大深度

也是深搜+回溯的思想,一条一条的路线找,找到更长的路线就更新。
(广搜也阔以呀,不过需要给记录下存入队列的结点所属的层数,加入它的子节点时就要在当前基础上+1了,从上到下的数,深搜就是从下往上的数)

	public int depth(){
        return depth(root);
    }
    private int depth(TreeNode<T> node){
        if(node==null){
            return 0;
        }
        return Math.max(depth(node.left),depth(node.right))+1;
    }

完整代码

import java.util.*;
public class SerchTree <T extends Comparable<? super T>> {
    private TreeNode root;
    private int size;
    private enum ModeEnum {
        pre("pre"),mid("mid"),after("after"),levelOrder("levelOrder");
        private String mode;
        ModeEnum(String mode){
            this.mode = mode;
        }
    }
    public int depth(){
        return depth(root);
    }
    private int depth(TreeNode<T> node){
        if(node==null){
            return 0;
        }
        return Math.max(depth(node.left),depth(node.right))+1;
    }
    public List<T> toList(String s){
        if(isEmploy()){
            return null;
        }
        ModeEnum mode = ModeEnum.valueOf(s);
        List<T> list = new ArrayList<>();
        switch (mode){
            case mid:
                mid(root,list);
                break;
            case pre:
                pre(root,list);
                break;
            case after:
                after(root,list);
                break;
            case levelOrder:
                levelOrder(root,list);
                break;
            default:
                mid(root,list);
        }
        return list;
    }
    private void levelOrder(TreeNode<T> root, List<T> list) {
        Queue<TreeNode<T>> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            TreeNode<T> t = queue.poll();
            if(t.left!=null){
                queue.offer(t.left);
            }
            if(t.right!=null){
                queue.offer(t.right);
            }
            list.add(t.val);
        }
    }
    private void after(TreeNode<T> root, List<T> list) {
        if(root==null){
            return;
        }
        after(root.left,list);
        after(root.right,list);
        list.add(root.val);
    }
    private void pre(TreeNode<T> root, List<T> list) {
        if(root==null){
            return;
        }
        list.add(root.val);
        pre(root.left,list);
        pre(root.right,list);
    }
    private void mid(TreeNode<T> node,List<T> list){
        if(node==null){
            return;
        }
        mid(node.left,list);
        list.add(node.val);
        mid(node.right,list);
    }
    static class TreeNode<T extends Comparable<? super T>> {
        T val;
        TreeNode<T> left;
        TreeNode<T> right;

        TreeNode(T t){
            val = t;
        }
    }
    public SerchTree(){

    }
    public int size() {
        return size;
    }

    public SerchTree(T val){
        root = new TreeNode(val);

    }
    public boolean isEmploy(){
        return root==null;
    }
    public void insert(T val){
        if(exist(val)){
            System.out.println("已存在");
            return;
        }else if(isEmploy()){
            root = new TreeNode<>(val);
        }else{
            insert(val,root);
        }
        size++;
    }
    public void delete(T val){
        root = delete(root,val);
        size--;
    }
    private TreeNode delete(TreeNode<T> root, T val) {
        if(root==null){
            return null;
        }
        if(root.val.compareTo(val)>0){
            root.left = delete(root.left,val);
        }else if(root.val.compareTo(val)<0){
            root.right = delete(root.right,val);
        }else{
            if(root.left!=null||root.right!=null){
                TreeNode<T> temp = root.left;
                while(temp.right!=null){
                    temp = temp.right;
                }
                root.val = temp.val;
                root.left = linked(root.left);
            }else if(root.left!=null){
                root = root.left;
            }else if(root.right!=null){
                root = root.right;
            }else {
                root = null;
            }
        }
        return root;
    }
    private TreeNode<T> linked(TreeNode treeNode){
        if(treeNode.right==null){
            return treeNode.left;
        }
        treeNode.right = linked(treeNode.right);
        return treeNode;
    }

    private void insert(T val,TreeNode<T> root){
        if(root.val.compareTo(val)<0){
            if(root.right==null){
                root.right = new TreeNode<>(val);
                return;
            }
            insert(val,root.right);
        }else {
            if(root.left==null){
                root.left = new TreeNode<>(val);
                return;
            }
            insert(val,root.left);
        }

    }
    private boolean exist(T val){
        return serch(val)!=null;
    }
    private TreeNode serch(T val){
        if(isEmploy()||val==root.val){
            return root;
        }
        return serch(root,val);
    }

    private TreeNode  serch(TreeNode<T> t,T val){
        if(t==null){
            return null;
        }
        if(t.val.compareTo(val)==0){
            return t;
        }
        if(t.val.compareTo(val)>0){
            return serch(t.left,val);
        }else {
            return serch(t.right,val);
        }
    }

    public static void main(String[] args){

        SerchTree<Integer> serchTree = new SerchTree<>();
        serchTree.insert(10);
        serchTree.insert(5);
        serchTree.insert(2);
        serchTree.insert(1);
        serchTree.insert(3);
        serchTree.insert(4);
        serchTree.insert(8);
        serchTree.insert(9);
        serchTree.insert(6);
        serchTree.insert(15);
        serchTree.insert(13);
        serchTree.insert(11);
        serchTree.delete(5);
        serchTree.insert(25);
        serchTree.insert(18);
        serchTree.insert(16);
        serchTree.insert(26);
        serchTree.delete(25);
        List<Integer> list = serchTree.toList("mid");
        for(int i:list){
            System.out.print(i+" ");
        }
        System.out.println();
        list = serchTree.toList("pre");
        for(int i:list){
            System.out.print(i+" ");
        }
        System.out.println();

        list = serchTree.toList("after");
        for(int i:list){
            System.out.print(i+" ");
        }
        System.out.println();

        list = serchTree.toList("levelOrder");
        for(int i:list){
            System.out.print(i+" ");
        }
        System.out.println();

        System.out.println(serchTree.depth());
        System.out.println(serchTree.size());
    }

}
//1 2 3 4 6 8 9 10 11 13 15 16 18 26
//        10 4 2 1 3 8 6 9 15 13 11 18 16 26
//        1 3 2 6 9 8 4 11 13 16 26 18 15 10
//        10 4 15 2 8 13 18 1 3 6 9 11 16 26
//        4
//        14

你可能感兴趣的:(算法/数据结构)