Tree简介

概念

树(Tree)是一种非线性的数据结构,它以分层的方式存储和组织数据。树由节点(Node)和边(Edge)组成。每个节点可以有零个或多个子节点,而除了根节点外,每个节点都有一个父节点。在一棵树中,根节点是位于顶部的唯一一个特殊节点。从根开始,通过边连接到其他子级节点,并且这些子级又可以作为父级来连接更多的子级。没有任何子级的节点称为叶子(Leaf),而具有至少一个子节点的元素被称为内部或非叶子节 (Internal or Non-Leaf) 节点。

特点

  1. 层次结构:每层都从上至下递增地排列,并且父级与其子级之间存在明确关联性。
  2. 唯一路径:从根到每个叶子只存在唯一路径。
  3. 无循环性:不能形成环路。

优点

  1. 层次性:树以层级的方式存储数据,这使得在查找、插入和删除等操作中具有良好的效率。相比于线性结构如数组或链表,树能更快速地定位到特定节点。
  2. 快速搜索和检索:树可以通过使用适当的搜索算法(比如二叉搜索树)来快速查找和检索特定元素。这对于处理大量数据并需要高效率查询或排序的场景非常重要。
  3. 灵活性:树可以动态增长和缩小,并且支持动态调整节点之间的连接关系。这使得它在各种应用中都能够灵活适应不同需求。

缺点

  1. 平衡问题:某些类型的树(如二叉搜索树)可能会因为插入或删除操作而导致不平衡,从而降低了其性能。需要采取平衡策略来解决这个问题,例如红黑树、AVL 树等。
  2. 内存开销较大:相比于线性结构,图形化表示以及需要额外指针引用子节点会占用更多内存空间。
  3. 操作复杂度不均衡:如果一棵树非常不平衡,可能会导致某些操作效率较低。例如,在一棵高度不平衡的二叉搜索树中进行查找操作时,时间复杂度可能最差达到 O(n)。

适用场景

  • 层次化数据模型需求(例如文件系统)。
  • 编译器和解析器中的语法分析。
  • 网络路由算法等领域。

二叉搜索树实现代码

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    public TreeNode(int val) {
        this.val = val;
        this.left = null;
        this.right = null;
    }
}

class BinarySearchTree {
    private TreeNode root;

    public BinarySearchTree() {
        root = null;
    }

    // 判断树是否为空
    public boolean isEmpty() {
        return root == null;
    }

    // 计算树的高度
    public int getHeight() {
        return getHeight(root);
    }

    private int getHeight(TreeNode node) {
        if (node == null)
            return 0;

        int leftHeight = getHeight(node.left);
        int rightHeight = getHeight(node.right);

        return Math.max(leftHeight, rightHeight) + 1;
    }

    // 插入节点
    public void insert(int value) {
        root = insertNode(root, value);
        System.out.println("root is " + root.val);
    }

    private TreeNode insertNode(TreeNode node, int value){
        if (node == null)
            return new TreeNode(value);

        if (value < node.val)
            node.left=insertNode(node.left,value);

        else if (value > node.val)
            node.right=insertNode(node.right,value);

        return node;
    }

    public void deleteNode(int key) {
        root = deleteRec(root, key);
    }

    private TreeNode deleteRec(TreeNode currentNode, int key) {
        if (currentNode == null) {
            return null;
        }

        if (key < currentNode.val) {      // 如果要删除的键小于当前结点,则继续在左侧递归查找并更新左侧孩子
            currentNode.left = deleteRec(currentNode.left, key);
        } else if (key > currentNode.val) {   // 如果要删除的键大于当前结点,则继续在右侧递归查找并更新右侧孩子
            currentNode.right = deleteRec(currentNode.right, key);
        } else {  // 当前结点是要被删掉的结点
            // 第一种和第二种情况: 没有左/右孩子或只有一个孩子
            if (currentNode.left == null) {
                return currentNode.right;
            } else if (currentNode.right == null) {
                return currentNode.left;
            }
            // 第三种情况: 有两个孩子
            // 找到右子树中的最小键值节点
            currentNode.val = minValue(currentNode.right);

            // 在右子树中递归删除最小键值节点
            currentNode.right = deleteRec(currentNode.right, currentNode.val);
        }

        return currentNode;   // 返回更新后的结点
    }

    private int minValue(TreeNode node) {
        int minv = node.val;
        while (node.left != null) {
            minv=node.left.val;
            node=node.left;
        }
        return minv ;
    }

    // 查找节点
    public boolean search(int key) {
        return searchKey(root, key);
    }

    private boolean searchKey(TreeNode currentNode ,int key){

        if(currentNode==null)
            return false;

        if(currentNode.val==key)
            return true;

        // 如果查找的值比当前节点小,则递归地在左子树中查找
        if(key<currentNode.val)
            return searchKey(currentNode.left,key);

        // 如果查找的值比当前节点大,则递归地在右子树中查找
        return searchKey(currentNode.right,key);
    }
    // 前序遍历二叉搜索树
    public void preorderTraversal() {
        preorder(root);
    }

    private void preorder(TreeNode node) {
        if (node != null) {
            System.out.print(node.val + " ");
            preorder(node.left);
            preorder(node.right);
        }
    }
    // 中序遍历二叉搜索树
    public void inorderTraversal() {
        inorder(root);
    }

    private void inorder(TreeNode node) {
        if (node != null) {
            inorder(node.left);
            System.out.print(node.val + " ");
            inorder(node.right);
        }
    }

    // 后序遍历二叉搜索树
    public void postorderTraversal() {
        postorder(root);
    }

    private void postorder(TreeNode node) {
        if (node != null) {
            postorder(node.left);
            postorder(node.right);
            System.out.print(node.val + " ");
        }
    }
}

常见操作示例

1、创建二叉搜索树

BinarySearchTree bst = new BinarySearchTree();

2、插入元素

// 构建二叉搜索树
bst.insert(5);
bst.insert(3);
bst.insert(7);
bst.insert(2);
bst.insert(4);
bst.insert(6);
bst.insert(8);
bst.insert(1);
bst.insert(9);
bst.insert(10);
//插入10个节点后,构建了一个如下结构的二叉搜索树:
//     	    5
//       /     \
//      3       7
//     / \     / \
//    2   4   6    8
//   /              \
//  1                9
//                     \
//                 	   10

3、获取高度

int height =bst.getHeight();
System.out.println("树的高度: " +height );

4、判断是否为空

System.out.println("是否为空: " +bst.isEmpty());

5、前序遍历

System.out.print("前序遍历结果: ");
bst.preorderTraversal();

6、中序遍历

System.out.println("中序遍历结果 :");
bst.inorderTraversal();

7、后序遍历

System.out.println("后序遍历结果: ");
bst.postorderTraversal();

8、节点搜索

System.out.println("当前树种是否存在节点5: " +bst.search(5));

9、删除节点

bst.deleteNode(3);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大宝贱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值