Android版数据结构与算法(八):二叉排序树

本文目录

前两篇文章我们学习了一些树的基本概念以及常用操作,本篇我们了解一下二叉树的一种特殊形式:二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree),亦称二叉搜索树。

一、二叉排序树定义

二叉排序树或者是一颗空树,或者是具有下列性质的二叉树:

  • 若它的左子树不为空,则左子树上所有结点的值均小于它的根结点的值
  • 若它的右子树不为空,则右子树上所有结点的值均大于它的根结点的值
  • 它的左,右子树也分别为二叉排序树

也就是说二叉排序树中左子树结点值均小于根结点值,右子树节点值均大于跟节点值,左右子树同样满足上述约定。

如下图,即为一颗二叉排序树:

由二叉树定义知道,我们通过中序遍历二叉树就可以按照从小到大顺序排列二叉树中所有元素。

如上图中序遍历结果为:35, 40, 42, 45, 50, 67

二、java代码实现二叉排序树核心方法

下面我们通过java代码实现二叉排序树中的几个核心方法

我们先看下每个结点类定义如下:

 1class TreeNode{
 2        private int data;
 3        private TreeNode leftChild;
 4        private TreeNode rightChild;
 5        private TreeNode parent;
 6
 7        public TreeNode(int data) {
 8            this.data = data;
 9            this.leftChild = null;
10            this.rightChild = null;
11            this.parent = null;
12        }
13}

很简单,每个结点记录自己以及左右孩子,父类的信息。

二叉排序树的创建(增加元素方法)

创建一颗二叉排序树就是不断往里面添加元素。 
整体思路为:

  • 判断整棵树根结点是否创建过,如果没有创建那么第一个加入进来的元素指定为根结点,方法返回。
  • 如果二叉排序树已经创建过,那么再往里面加入元素需要先找出其父节点,然后将要插入的元素挂载到父节点下即可。
  • 经过上面过程找出其父结点,这里只需创建节点,挂载到父节点下即可,指定为父节点左孩子还是右孩子只需比较一下元素大小即可。

源码:

 1    public TreeNode put(int data){
 2        TreeNode node = root;
 3        TreeNode parent = null;
 4        //判断二叉排序树根结点是否存在,不存在则创建
 5        if (root == null){
 6            root = new TreeNode(data);
 7            return root;
 8        }
 9        //查找其父类
10        while (node != null){
11            parent = node;//记录其父亲节点
12            if (data > node.data){
13                node = node.rightChild;
14            }else if (data < node.data){
15                node = node.leftChild;
16            }else {
17                //已经存在则直接返回
18                return node;
19            }
20        }
21        //创建新节点并插入原有树中
22        node = new TreeNode(data);
23        if (data < parent.data){
24            parent.leftChild = node;
25        }else {
26            parent.rightChild = node;
27        }
28        node.parent = parent;
29        return node;
30    }
二叉排序树的查找

二叉排序树中查找比较简单,思路为:

  • 当前结点与查找的数据比较,相等则返回
  • 若小于当前结点则从左子树查找即可
  • 若大于当前结点则从右子树查找即可
    重复上述过程,这里就看出二分查找思想了

源码:

 1    public TreeNode searchNode(int data) {
 2        TreeNode node = root;
 3        if (node == null){
 4            return null;
 5        }else {
 6            while (node != null && data != node.data){
 7                if (data < node.data){
 8                    node = node.leftChild;
 9                }else {
10                    node = node.rightChild;
11                }
12            }
13        }
14        return node;
15    }
二叉排序树的删除

二叉排序树的删除操作分4中情况:

  • 若要删除的结点无左右孩子也就是叶子结点,那么直接删除即可,将其父节点左或者右孩子置null即可
  • 若要删除的结点有左孩子无右孩子,则只需要将删除结点的左孩子与其父节点建立关系即可
  • 若要删除的结点有右孩子无左孩子,则只需要将删除结点的右孩子与其父节点建立关系即可
  • 若要删除的结点左右孩子均有,就需要选一个结点将其替换,这里需要保证选取的结点保证比左子树都大,右子树都小,可以选取左子树中最大的结点,或者右子树中最小的结点,并且需要将选取的结点从二叉排序树中删除。

源码:这里我们选取右子树最小的结点

 1    public void deleteNode(int data){
 2        TreeNode node = searchNode(data);
 3        if (node == null){
 4            throw new RuntimeException("未找到要删除的节点");
 5        }else {
 6            delete(node);
 7        }
 8    }
 9
10    private void delete(TreeNode node) {
11        if (node == null){
12            throw new RuntimeException("未找到要删除的节点");
13        }else {
14            TreeNode parent = node.parent;
15            //删除的节点无左右孩子
16            if (node.leftChild == null && node.rightChild == null){
17                if (parent.leftChild == node){
18                    parent.leftChild = null;
19                }else {
20                    parent.rightChild = null;
21                }
22                return;
23            }
24            //删除的节点有左无右
25            if (node.leftChild != null
26                    && node.rightChild == null){
27                if (parent.leftChild == node){
28                    parent.leftChild = node.leftChild;
29                }else {
30                    parent.rightChild = node.leftChild;
31                }
32                return;
33            }
34            //删除的节点有右无左
35            if (node.leftChild == null
36                    && node.rightChild != null){
37                if (parent.leftChild == node){
38                    parent.leftChild = node.rightChild;
39                }else {
40                    parent.rightChild = node.rightChild;
41                }
42                return;
43            }
44            //删除的结点左右都有
45            TreeNode rightMinNode = getRightMinNode(node.rightChild);
46            delete(rightMinNode);
47            node.data = rightMinNode.data;
48        }
49    }
50
51    //获取右子树最小的结点
52    private TreeNode getRightMinNode(TreeNode node) {
53        TreeNode minNode = node;
54        while (minNode != null && minNode.leftChild != null){
55            minNode = minNode.leftChild;
56        }
57        System.out.println("minNode" + minNode.data);
58        return minNode;
59    }
接下来我们测试一下

测试代码:

 1 SearchBinaryTree ss = new SearchBinaryTree();
 2 int[] array = {77,88,34,55,66,2,34,67,78};
 3 for (int data : array) {
 4     ss.put(data);
 5 }
 6 ss.midIter(ss.getRoot());
 7 System.out.println();
 8 SearchBinaryTree.TreeNode node = ss.searchNode(66);
 9 System.out.println("find node:"+node.getData());
10 ss.deleteNode(66);
11 SearchBinaryTree.TreeNode dnode = ss.searchNode(66);
12 if (dnode != null){
13     System.out.println("find node:"+node.getData());
14 }else {
15     System.out.println("not find node");
16 }
17 ss.midIter(ss.getRoot());

打印信息如下:

1    2 34 55 66 67 77 78 88
2    find node:66
3    not find node
4    2 34 55 67 77 78 88

三、二叉排序树性能问题

二叉排序树最好的情况下其查找性能是很高的,接近二分查找法。 
但是在有些情况下构建出的二叉排序树类似一个链表,其查找性能为O(n),如下图:

构建出这样的树肯定不是我们希望的,需要调整此树达到平衡的效果,这里就需要二叉平衡树了(AVL树),关于AVL树会在后续篇章介绍,这里知道二叉平衡树有这个问题就可以了。

四、总结

本篇主要介绍了二叉平衡树以及Java代码实现其核心方法,希望你能掌握其与普通二叉树的区别,以及其存在的问题,好了,本片到此为止,希望对你有用。

声明:文章将会陆续搬迁到个人公众号,以后也会第一时间发布到个人公众号,及时获取文章内容请关注公众号

最后附上整个类的全部源码,拷贝过去就可以用了:

  1    public class SearchBinaryTree {
  2
  3    private TreeNode root;//二叉树根结点
  4
  5    public TreeNode getRoot() {
  6        return root;
  7    }
  8
  9    //中序遍历二叉排序树:按照从小到大排序
 10    public void midIter(TreeNode node){
 11        if (node == null){
 12            return;
 13        }
 14        midIter(node.leftChild);
 15        System.out.print(" "+node.data);
 16        midIter(node.rightChild);
 17    }
 18
 19    public TreeNode put(int data){
 20        TreeNode node = root;
 21        TreeNode parent = null;
 22        //判断二叉排序树根结点是否存在,不存在则创建
 23        if (root == null){
 24            root = new TreeNode(data);
 25            return root;
 26        }
 27        //查找其父类
 28        while (node != null){
 29            parent = node;//记录其父亲节点
 30            if (data > node.data){
 31                node = node.rightChild;
 32            }else if (data < node.data){
 33                node = node.leftChild;
 34            }else {
 35                //已经存在则直接返回
 36                return node;
 37            }
 38        }
 39        //创建新节点并插入原有树中
 40        node = new TreeNode(data);
 41        if (data < parent.data){
 42            parent.leftChild = node;
 43        }else {
 44            parent.rightChild = node;
 45        }
 46        node.parent = parent;
 47        return node;
 48    }
 49
 50    public void deleteNode(int data){
 51        TreeNode node = searchNode(data);
 52        if (node == null){
 53            throw new RuntimeException("未找到要删除的节点");
 54        }else {
 55            delete(node);
 56        }
 57    }
 58
 59    private void delete(TreeNode node) {
 60        if (node == null){
 61            throw new RuntimeException("未找到要删除的节点");
 62        }else {
 63            TreeNode parent = node.parent;
 64            //删除的节点无左右孩子
 65            if (node.leftChild == null && node.rightChild == null){
 66                if (parent.leftChild == node){
 67                    parent.leftChild = null;
 68                }else {
 69                    parent.rightChild = null;
 70                }
 71                return;
 72            }
 73            //删除的节点有左无右
 74            if (node.leftChild != null
 75                    && node.rightChild == null){
 76                if (parent.leftChild == node){
 77                    parent.leftChild = node.leftChild;
 78                }else {
 79                    parent.rightChild = node.leftChild;
 80                }
 81                return;
 82            }
 83            //删除的节点有右无左
 84            if (node.leftChild == null
 85                    && node.rightChild != null){
 86                if (parent.leftChild == node){
 87                    parent.leftChild = node.rightChild;
 88                }else {
 89                    parent.rightChild = node.rightChild;
 90                }
 91                return;
 92            }
 93            //删除的结点左右都有
 94            TreeNode rightMinNode = getRightMinNode(node.rightChild);
 95            delete(rightMinNode);
 96            node.data = rightMinNode.data;
 97        }
 98    }
 99
100    private TreeNode getRightMinNode(TreeNode node) {
101        TreeNode minNode = node;
102        while (minNode != null && minNode.leftChild != null){
103            minNode = minNode.leftChild;
104        }
105        System.out.println("minNode" + minNode.data);
106        return minNode;
107    }
108
109    public TreeNode searchNode(int data) {
110        TreeNode node = root;
111        if (node == null){
112            return null;
113        }else {
114            while (node != null && data != node.data){
115                if (data < node.data){
116                    node = node.leftChild;
117                }else {
118                    node = node.rightChild;
119                }
120            }
121        }
122        return node;
123    }
124
125
126    public class TreeNode{
127        private int data;
128        private TreeNode leftChild;
129        private TreeNode rightChild;
130        private TreeNode parent;
131
132        public TreeNode(int data) {
133            this.data = data;
134            this.leftChild = null;
135            this.rightChild = null;
136            this.parent = null;
137        }
138
139        public int getData() {
140            return data;
141        }
142
143        public void setData(int data) {
144            this.data = data;
145        }
146
147        public TreeNode getLeftChild() {
148            return leftChild;
149        }
150
151        public void setLeftChild(TreeNode leftChild) {
152            this.leftChild = leftChild;
153        }
154
155        public TreeNode getRightChild() {
156            return rightChild;
157        }
158
159        public void setRightChild(TreeNode rightChild) {
160            this.rightChild = rightChild;
161        }
162
163        public TreeNode getParent() {
164            return parent;
165        }
166
167        public void setParent(TreeNode parent) {
168            this.parent = parent;
169        }
170    }
171}

原文地址:https://www.cnblogs.com/leipDao/p/10058144.html

时间: 2024-10-08 19:36:33

Android版数据结构与算法(八):二叉排序树的相关文章

数据结构与算法问题 二叉排序树

题目描写叙述: 二叉排序树,也称为二叉查找树. 能够是一颗空树.也能够是一颗具有例如以下特性的非空二叉树: 1. 若左子树非空,则左子树上全部节点keyword值均不大于根节点的keyword值: 2. 若右子树非空,则右子树上全部节点keyword值均不小于根节点的keyword值. 3. 左.右子树本身也是一颗二叉排序树. 如今给你N个keyword值各不同样的节点,要求你按顺序插入一个初始为空树的二叉排序树中,每次插入后成功后.求对应的父亲节点的keyword值.假设没有父亲节点,则输出-

Java数据结构和算法(八)--红黑树与2-3树

红黑树规则: 1.根节点与叶节点都是黑色节点 2.每个红色节点的两个子节点都是黑色节点,反之,不做要求,换句话说就是不能有连续两个红色节点 3.从根节点到所有叶子节点上的黑色节点数量是相同的 一般对红黑树的讲述都是先给出这样的定义,这样想对不太容易理解的,而在算法4一书中,直接跳过这些规则,而讲述了红黑树与2-3树的等价性 如果我们先了解2-3树,理解了红黑树与2-3树之间的关系,回过头就会发现红黑树不难 2-3树: 2-3树满足二分搜索树的基本性质,但是不是二叉树 2-3树节点可以存放一个元素

C语言版数据结构及算法_快速排序

/* 参数: a:数组首地址 left:需要排序的数组的开始位置 right:需要排序的数组的结束位置 */ void qSort(int *a,int left,int right){ //快速排序 if (left>=right) { return; }else{ int value=a[left]; int initLeft=left; int initRight=right; while (left!=right) { while (value<a[right]) { right--;

Java版数据结构插入数据时遇到的结点为空的问题

在演示Java版数据结构与算法教材中的头插法代码时遇到了空结点问题 . 先上代码. 链表类 import java.util.Scanner; public class ListLinked<T> { ListLinkedNode<Integer> head=new ListLinkedNode<Integer>();//声明头结点 //添加结点 public void addFromHead(int e){ ListLinkedNode<Integer>

浅谈算法和数据结构: 七 二叉查找树 八 平衡查找树之2-3树 九 平衡查找树之红黑树 十 平衡查找树之B树

http://www.cnblogs.com/yangecnu/p/Introduce-Binary-Search-Tree.html 前文介绍了符号表的两种实现,无序链表和有序数组,无序链表在插入的时候具有较高的灵活性,而有序数组在查找时具有较高的效率,本文介绍的二叉查找树(Binary Search Tree,BST)这一数据结构综合了以上两种数据结构的优点. 二叉查找树具有很高的灵活性,对其优化可以生成平衡二叉树,红黑树等高效的查找和插入数据结构,后文会一一介绍. 一 定义 二叉查找树(B

C语言版数据结构算法

C语言版数据结构算法 C语言数据结构具体算法 https://pan.baidu.com/s/19oLoEVqV1I4UxW7D7SlwnQ C语言数据结构演示软件 https://pan.baidu.com/s/1u8YW897MjJkoOfsbHuadFQ 在上一篇的FIFO中就是基于数据结构思维中的队列实现的,而基本的数据结构内容还有 算法效率分析.线性表.栈和队列.串.数组和广义表.树和二叉树.图.查表.排序.动态存储管理 上面两个链接就是<数据结构(C语言版)>严蔚敏教授严奶奶的书籍

重读《学习JavaScript数据结构与算法-第三版》-第2章 ES和TS

定场诗 八月中秋白露,路上行人凄凉: 小桥流水桂花香,日夜千思万想. 心中不得宁静,清早览罢文章, 十年寒苦在书房,方显才高志广. 前言 洛伊安妮·格罗纳女士所著的<学习JavaScript数据结构与算法>第三版于2019年的5月份再次刊印发行,新版内容契合当下,实为JavaScript开发人员的必备之佳作.有幸重读此版,与诸君分享共勉. 内容提要 此章节为第2章-ECMAScript与TypeScript概述,主要介绍了JS和TS的相关概念,以及在JS新版本中的新特性:let.解构.箭头函数

算法入门《数据结构与算法图解》+《我的第一本算法书》+《学习JavaScript数据结构与算法第3版》

最近几年学前端的人会越来越多,再加上前端的范围越来越广,从前端发展为全栈,数据结构和算法的功底要求势必将越来越高. <数据结构与算法图解>电子书及代码是数据结构与算法的入门指南,不局限于某种特定语言,略过复杂的数学公式,用通俗易懂的方式针对编程初学者介绍数据结构与算法的基本概念,培养编程逻辑.主要内容包括:为什么要了解数据结构与算法,大O表示法及其代码优化利用,栈.队列等的合理使用,等等. <算法图解>电子书非常的体贴,看起来也很快,用图来解释算法是非常好的想法,可作为学习数据结构

重读《学习JavaScript数据结构与算法-第三版》- 第3章 数组(一)

定场诗 大将生来胆气豪,腰横秋水雁翎刀. 风吹鼍鼓山河动,电闪旌旗日月高. 天上麒麟原有种,穴中蝼蚁岂能逃. 太平待诏归来日,朕与先生解战袍. 此处应该有掌声... 前言 读<学习JavaScript数据结构与算法>- 第3章 数组,本节将为各位小伙伴分享数组的相关知识:概念.创建方式.常见方法以及ES6数组的新功能. 数组 数组是最简单的内存数据结构,用于存储一系列同一种数据类型的值. 注:虽然数组支持存储不同类型的值,但建议遵守最佳实践. 一.数组基础 创建和初始化数组 new Array