数据结构 - 从二叉搜索树说到AVL树(一)之二叉搜索树的操作与详解(Java)

  二叉搜索树(Binary Search Tree),简称BST,顾名思义,一颗可以用于搜索的二叉树。BST在数据结构中占有很重要的地位,一些高级树结构都是其的变种,例如AVL树、红黑树等,因此理解BST对于后续树结构的学习有很好的作用。同时利用BST可以进行排序,称为二叉排序,也是很重要的一种思想。

  二叉树的性质:任意一个节点的所有左子树元素都比该元素值要小,而所有右子树元素都比该元素值要大。

  符合该性质的二叉树就是一颗二叉搜索树,当然前提下是树中不允许有重复元素。

  所有的二叉搜索树的中序遍历序列都是一个顺序序列, 一下的几种都是二叉搜索树

            

  接下来讲二叉搜索树的三个主要操作:查找,增加,删除。

  一、查找

    二叉搜索树本来就是用于查找数据的一种结构,主要步骤是:

      ① 选择根节点作为当前节点

      ② 如果当前节点为null,则返回false表示找不到该元素

      ③ 如果当前节点不为null,判断当前节点是否与所搜索元素相等,如相等,则返回true表示能找到该元素

      ④ 如果当前节点的值比所搜索值小,则选择当前节点的左节点作为当前节点,比搜索值大则选择右节点作为当前节点,然后从②循环过程

  二、增加

    二叉搜索树增加节点重点是根据查找元素的过程找到该节点的插入位置:

      ① 如果根节点为空,则当前插入(增加)的节点为二叉树的根,如根节点不为空,设置根节点为当前节点

      ② 如果当前节点的值与插入节点的值相等,返回false表示插入失败,节点值已存在于树中

      ② 如插入节点的值比当前节点的值小,且当前节点的左子树为空,则把插入节点增加到当前节点的左子树,设置插入节点的父节点为当前节点并返回true表示插入成功,如左子树不为空,设置 当前节点的左子树为当前节点。如果插入节点的值比当前节点的值大,且当前节点的右子树为空,则把插入节点增加到当前节点的右子树,设置插入节点的父节点为当前节点并返回true,如右子树不为空,设置当前节点的右子树为当前节点。从②循环过程

    具体代码如下:

    public boolean insert(int elem) {
        TreeNode node = new TreeNode(elem);
        if (null == this.root) {
            this.root = node;
            return true;
        } else {
            return insertChild(this.root, node);
        }
    }
    /**
     * insert the newNode to the child position of parent node
     * @param parent
     * @param newNode
     * @return true if the newNode insert successfully or false if the newNode have been exist
     */
    private boolean insertChild(TreeNode parent, TreeNode newNode) {
        if (parent.getElem() == newNode.getElem()) {
            return false;
        } else if (parent.getElem() > newNode.getElem()) {
            if (null  == parent.getLeft()) {
               parent.setLeft(newNode);
               newNode.setParent(parent);
               return true;
            } else {
               return insertChild(parent.getLeft(), newNode);
            }
        } else {
            if (null == parent.getRight()) {
               parent.setRight(newNode);
               newNode.setParent(parent);
               return true;
            } else {
               return insertChild(parent.getRight(), newNode);
            }
        }
    }

  三、删除

    二叉搜索树的删除操作重点在于删除这个节点之后对其他节点的重组,根据删除节点位置又分为以下几种情况:

      情况1 删除节点为叶子节点:把父节点对应的子树设为空

      情况2 删除节点只有左子树或只有右子树:把父节点对应的子树指向删除节点的左子树或者右子树,并把左子树或右子树的父节点指向删除节点的父节点

      情况3 删除节点的左子树和右子树均不为空:找到删除节点的前驱节点,把前驱节点的值代替删除节点的值,其他不做任何操作,把这个前驱节点作为删除节点,则该情况转换成情况1或者情况2

      比如想删除节点 5

         >>>       >>>   

    这样就换成了删除原来的节点4,变成了情况1,删除掉原来的节点4之后,剩下的依然是一颗二叉搜索树。

    具体代码:

    /**
     * delete the node which element equals to parameter elem
     * @param elem
     * @return true if the node can be found and delete otherwise false
     */
    public boolean delete(int elem) {
        if (null == this.root) {
            return false;
        } else {
            TreeNode node = this.root;
            // find out the node need to be deleted
            while (null != node) {
                if (node.getElem() == elem) {
                    deleteNode(node);
                    return true;
                } else if (node.getElem() > elem) {
                    node = node.getLeft();
                } else {
                    node = node.getRight();
                }
            }
            return false;
        }
    }
    private void deleteNode(TreeNode node) {
        if (null == node.getLeft() && null == node.getRight()) {
            // deleted node is a leave
            if (null  == node.getParent()) {
                // deleted node is root
                this.root = null;
            } else if (node == node.getParent().getLeft()) {
                // deleted node is the left child of its parent
                node.getParent().setLeft(null);
            } else {
                // deleted node is the right child of its parent
                node.getParent().setRight(null);
            }
        } else if (null == node.getLeft()) {
            // deleted node only hae right child
            if (null  == node.getParent()) {
                this.root = node.getRight();
            } else if (node == node.getParent().getLeft()) {
                node.getParent().setLeft(node.getRight());
            } else {
                node.getParent().setRight(node.getRight());
            }
            node.getRight().setParent(node.getParent());
        } else if (null == node.getRight()) {
            // deleted node only have left child
            if (null  == node.getParent()) {
                this.root = node.getLeft();
            } else if (node == node.getParent().getLeft()) {
                node.getParent().setLeft(node.getLeft());
            } else {
                node.getParent().setRight(node.getLeft());
            }
            node.getLeft().setParent(node.getParent());
        } else {
            // deleted node have both left & right children
            // find out the precursor of deleted node
            // the precursor node replace the position of deleted node
            TreeNode pre = node.getLeft();
            while (null != pre.getRight()) {
                pre  = pre.getRight();
            }
            // swap the elem of precursor node and deleted node
            // then delete the precursor node
            TreeUtils.swapTreeElem(pre, node);
            deleteNode(pre);
        }
    }

写个小程序测试一下:

输入测试数据:10 5 2 7 6 18 13 -1(-1是结束输入,不作为一个元素值)

1. insert
2. delete
3. search
4. print
5. exit
->1
->10 5 2 7 6 18 13 -1
insert success

看一下树的结构,显示树结构的需要顺时针转90°来看,并自己想象节点连线。。

1. insert
2. delete
3. search
4. print
5. exit
->4
-
    18
        13
10
        7
            6
    5
        2
-

删除节点 5 测试效果

1. insert
2. delete
3. search
4. print
5. exit
->2
->5
delete success
--------------------------------------------------------------
1. insert
2. delete
3. search
4. print
5. exit
->4
-
    18
        13
10
        7
            6
    2
-

至此, 二叉搜索树的操作及具体实现完成,如有不妥之处,欢迎指出斧正。

尊重知识产权,转载请标明出处并通知作者。

原文地址:https://www.cnblogs.com/GNLin0820/p/9120331.html

时间: 2024-11-07 03:11:25

数据结构 - 从二叉搜索树说到AVL树(一)之二叉搜索树的操作与详解(Java)的相关文章

AVL平衡树(详解)-JAVA版本

平衡二叉树在进行插入操作的时候可能出现不平衡的情况,AVL树即是一种自平衡的二叉树. 它通过旋转不平衡的节点来使二叉树重新保持平衡,并且查找.插入和删除操作在平均和最坏情况下时间复杂度都是O(log n) AVL树的旋转一共有四种情形,注意所有旋转情况都是围绕着使得二叉树不平衡的第一个节点展开的. RBT VS AVL: 实际上插入AVL树和红黑树的速度取决于你所插入的数据.如果你的数据分布较好,则比较宜于采用AVL树(例如随机产生系列数), 但是如果你想处理比较杂乱的情况,则红黑树是比较快的,

数据结构之---C语言实现平衡二叉树(AVL树)

//AVL(自动平衡二叉树) #include <stdio.h> #include <stdlib.h> typedef int ElemType; //每个结点的平均值 typedef enum { EH = 0, LH = 1, RH = -1 }bh_t; typedef enum { FALSE = 0, TRUE = 1 }bool_t; //定义平衡二叉树 typedef struct BSTNode { ElemType key; //平衡值 int bf; str

详解java中的数据结构

线性表,链表,哈希表是常用的数据结构,在进行Java开发时,JDK已经为我们提供了一系列相应的类来实现基本的数据结构.这些类均在java.util包中.本文试图通过简单的描述,向读者阐述各个类的作用以及如何正确使用这些类. Collection ├List │├LinkedList │├ArrayList │└Vector │ └Stack └Set Map ├Hashtable ├HashMap └WeakHashMap Collection接口 Collection是最基本的集合接口,一个C

【数据结构】第9章 查找! (二叉搜索树BST AVL树 B-(+)树 字典树 HASH表)

难产的笔记...本来打算用1天 结果前前后后拖了5天 §9.1 静态查找表 9.1.1 顺序表的查找 各种扫 自己脑补吧 复杂度O(n) 9.1.2 有序表的查找 若表是单调的,则可以利用二分查找.复杂度O(logn) 9.1.3 静态树表的查找 见 http://blog.csdn.net/area_52/article/details/43795837 9.1.4 索引顺序表的查找 建立索引表查找 §9.2 动态查找表 动态查找表的特点是,表结构本身是在查找过程中动态生成的,即对于给定值ke

二叉树、二叉搜索树、AVL树的java实现

数据结构一直都是断断续续的看,总是觉得理解的不够深入,特别是对树的理解,一直都很浅显,今儿又看了一遍,来做个总结吧. 首先,树中的一些概念: 1.树的节点包含一个数据元素,以及若干指向其子树的分支.节点拥有的子树的数量称为节点的度.节点的最大层次称为树的深度或高度. 2.二叉树是一种树形结构,其特点是每个节点至多有两棵子树,且子树有左右之分,次序不能随意颠倒. 3.满二叉树:一棵深度为k且有2^k - 1个节点的二叉树,称之为满二叉树. 4.完全二叉树:对一个深度为k,节点个数为n的二叉树,当且

平衡二叉搜索树(AVL树)的原理及实现源代码(有图文详解和C++、Java实现代码)

一.AVL树(平衡二叉搜索树)是什么? AVL树是根据它的发明者G.M. Adelson-Velsky和E.M. Landis命名的.AVL树本质上还是一棵二叉搜索树,它的特点是: 1.本身首先是一棵二叉搜索树. 2.带有平衡条件:每个非叶子结点的左右子树的高度之差的绝对值(平衡因子)最多为1. 例如: 5             5 / \            /  \ 2   6         2   6 / \    \         / \ 1  4   7       1  4

算法二叉搜索树之AVL树

最近学习了二叉搜索树中的AVL树,特在此写一篇博客小结. 1.引言 对于二叉搜索树而言,其插入查找删除等性能直接和树的高度有关,因此我们发明了平衡二叉搜索树.在计算机科学中,AVL树是最先发明的自平衡二叉搜索树.在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树.对于N个节点的AVL树,由于树高被限制为lgN,因此其插入查找删除操作耗时为O(lgN). 2.旋转 在讲解关键步骤插入与删除以前,首先我们先定义一些辅助用的操作:旋转.旋转分为左旋和右旋,其示意图如下: 相信上

《数据结构与算法分析:C语言描述》复习——第四章“树”——AVL树

2014.06.15 16:22 简介: AVL树是一种高度平衡的二叉搜索树,其命名源自于联合发明算法的三位科学家的名字的首字母.此处“平衡”的定义是:任意节点的左右子树的高度相差不超过1.有了这个平衡的性质,使得AVL树的高度H总是接近log(N),因此各种增删改查的操作的复杂度能够保证在对数级别.没有bad case是AVL树与普通的二叉搜索树的最大区别.为了实现平衡性质,我们需要记录每个节点的高度(或者平衡因子)来检测不平衡的情况.为了修正高度不平衡,需要用到“旋转”的方法,分为单旋转和双

java数据结构与算法之平衡二叉树(AVL树)的设计与实现

[版权申明]未经博主同意,不允许转载!(请尊重原创,博主保留追究权) http://blog.csdn.net/javazejian/article/details/53892797 出自[zejian的博客] 关联文章: java数据结构与算法之顺序表与链表设计与实现分析 java数据结构与算法之双链表设计与实现 java数据结构与算法之改良顺序表与双链表类似ArrayList和LinkedList(带Iterator迭代器与fast-fail机制) java数据结构与算法之栈(Stack)设