树的入门


树是由n(n>=1)个有限结点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。

二叉树就是度不超过2的树(每个结点最多有两个子结点)

二叉树的结点类

 private class Node<Key,Value>{
	//存储键
	public Key key;
	//存储值
	private Value value;
	//记录左子结点
	public Node left;
	//记录右子结点
	public Node right;
	public Node(Key key, Value value, Node left, Node right) {
		this.key = key;
		this.value = value;
		this.left = left;
		this.right = right;
	}
}

1.获取树中元素的个数

public int size() {
        return N;
    }

2.向树中添加元素key-value

public void put(Key key, Value value) {
        root = put(root, key, value);
}

3.向指定的树x中添加key-value,并返回添加元素后新的树

private Node put(Node x, Key key, Value value) {
        //如果子树x为空
        if (x == null) {
            N++;
            return new Node(key, value, null, null);
        }
        //如果子树x不为空
        //比较x节点的键和key的大小:
        int i = key.compareTo(x.key);
        if (i > 0) {
            //如果key大于x节点的键,则继续找x节点的右子树
            x.right = put(x.right, key, value);
        } else if (i < 0) {
            //如果key小于x节点的键,则继续找x节点的左子树
            x.left = put(x.left, key, value);
        } else {
            //如果key等于x节点的键,则替换x节点的值为value即可
            x.value = value;
        }
        return x;

    }

4.从指定的树x中,查找key对应的值

public Value get(Node x, Key key) {
        if (x == null) {
            return null;
        }
        int i = key.compareTo(x.key);
        if (i > 0) {
            return get(x.right, key);
        } else if (i < 0) {
            return get(x.left, key);
        } else {
            return x.value;
        }
    }

5.删除指定树x中的key对应的value,并返回删除后的新树

public Node delete(Node x, Key key) {
        if (x == null) {
            return null;
        }
        int cmp = key.compareTo(x.key);
        if (cmp > 0) {
            //新结点的key大于当前结点的key,继续找当前结点的右子结点
            x.right = delete(x.right, key);
        } else if (cmp < 0) {
            //新结点的key小于当前结点的key,继续找当前结点的左子结点
            x.left = delete(x.left, key);
        } else {
            //新结点的key等于当前结点的key,当前x就是要删除的结点
            //个数-1
            N--;
            //得找到右子树中最小的节点
            //1.如果当前结点的右子树不存在,则直接返回当前结点的左子结点
            if (x.right == null) {
                return x.left;
            }
            //2.如果当前结点的左子树不存在,则直接返回当前结点的右子结点
            if (x.left==null){
                return x.right;
            }
            //3.当前结点的左右子树都存在
            //3.1找到右子树中最小的结点
            Node minNode=x.right;
            while (minNode.left!=null){
                minNode=minNode.left;
            }
            //3.2删除右子树中最小的结点
            Node n=x.right;
            while (n.left!=null){
                if (n.left.left==null){
                    n.left=null;
                }else {
                    n=n.left;
                }
            }
            //3.3让被删除结点的左子树称为最小结点minNode的左子树,
            minNode.left=x.left;
            // 让被删除结点的右子树称为最小结点minNode的右子树
            minNode.right=x.right;
            //3.4让被删除结点的父节点指向最小结点minNode
            x = minNode;
        }
        return x;
    }

6.找出指定树x中最小的键所在的结点

private Node min(Node x){
        if (x.left!=null){
            return min(x.left);
        }else{
            return x;
        }
    }

7.找出指定树x中最大键所在的结点

prpublic Node max(Node x){
        if (x.right!=null){
            return max(x.right);
        }else{
            return x;
        }
    }

8.使用前序遍历,把指定树x中的所有键放入到keys队列中

前序遍历:先访问根结点,然后再访问左子树,最后访问右子树

private void preErgodic(Node x,Queue<Key> keys){
        if (x==null){
            return;
        }
        //1.把当前结点的key放入到队列中;
        keys.enqueue(x.key);
        //2.找到当前结点的左子树,如果不为空,递归遍历左子树
        if (x.left!=null){
            preErgodic(x.left,keys);
        }
        //3.找到当前结点的右子树,如果不为空,递归遍历右子树
        if (x.right!=null){
            preErgodic(x.right,keys);
        }
    }

9.使用中序遍历,把指定树x中的所有键放入到keys队列中

中序遍历:先访问左子树,中间访问根节点,最后访问右子树

private void midErgodic(Node x,Queue<Key> keys){
        if (x==null){
            return;
        }

        //1.找到当前结点的左子树,如果不为空,递归遍历左子树
        if (x.left!=null){
            midErgodic(x.left,keys);
        }
        //2.把当前结点的key放入到队列中;
        keys.enqueue(x.key);
        //3.找到当前结点的右子树,如果不为空,递归遍历右子树
        if (x.right!=null){
            midErgodic(x.right,keys);
        }
    }

10.使用后序遍历,把指定树x中的所有键放入到keys队列中

后序遍历:先访问左子树,再访问右子树,最后访问根节点

private void afterErgodic(Node x,Queue<Key> keys){
        if (x==null){
            return;
        }

        //1.找到当前结点的左子树,如果不为空,递归遍历左子树
        if (x.left!=null){
            midErgodic(x.left,keys);
        }

        //2.找到当前结点的右子树,如果不为空,递归遍历右子树
        if (x.right!=null){
            afterErgodic(x.right,keys);
        }
        //3.把当前结点的key放入到队列中;
        keys.enqueue(x.key);
    }

11.计算指定树的最大深度

private int maxDepth(Node x) {
    //1.如果根结点为空,则最大深度为0;
        if (x == null) {
            return 0;
        }
        int max = 0;
        int maxL = 0;
        int maxR = 0;
        //2.计算左子树的最大深度;
        if (x.left != null) {
            maxL = maxDepth(x.left);
        }
        //3.计算右子树的最大深度;
        if (x.right != null) {
            maxR = maxDepth(x.right);
        }
        //4.当前树的最大深度=左子树的最大深度和右子树的最大深度中的较大者+1
        max = maxL > maxR ? maxL + 1 : maxR + 1;
        return max;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值