1. 二叉查找树简介
二叉查找树(Binary Search Tree),又被称为二叉搜索树。
它是特殊的二叉树:对于二叉树,假设x为二叉树中的任意一个结点,x节点包含关键字key,节点x的key值记为key[x]。如果y是x的左子树中的一个结点,则key[y] <= key[x];如果y是x的右子树的一个结点,则key[y] >= key[x]。那么,这棵树就是二叉查找树。如下图所示
在二叉查找树中:
- 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值
- 任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值
- 任意节点的左、右子树也分别为二叉查找树
- 没有键值相等的节点(no duplicate nodes)
2. 二叉查找树的Java实现
2.1 二叉查找树节点的定义
|
|
BSTree是二叉树,它保护了二叉树的根节点mRoot;mRoot是BSTNode类型,而BSTNode是二叉查找树的节点,它是BSTree的内部类。BSTNode包含二叉查找树的几个基本信息:
- key – 它是关键字,是用来对二叉查找树的节点进行排序的。
- left – 它指向当前节点的左孩子。
- right – 它指向当前节点的右孩子。
- parent – 它指向当前节点的父结点。
2.2 遍历
这里讲解前序遍历、中序遍历、后序遍历3种方式。
2.2.1 前序遍历
若二叉树非空,则执行以下操作:
- 访问根结点;
- 先序遍历左子树;
- 先序遍历右子树。
前序遍历代码
|
|
2.2.2 中序遍历
若二叉树非空,则执行以下操作:
(01) 中序遍历左子树;
(02) 访问根结点;
(03) 中序遍历右子树。
中序遍历代码
|
|
2.3 后序遍历
若二叉树非空,则执行以下操作:
(01) 后序遍历左子树;
(02) 后序遍历右子树;
(03) 访问根结点。
后序遍历代码
|
|
看看下面这颗树的各种遍历方式:
对于上面的二叉树而言,
- 前序遍历结果: 3 1 2 5 4 6
- 中序遍历结果: 1 2 3 4 5 6
- 后序遍历结果: 2 1 4 6 5 3
2.4 层序遍历
所谓层序遍历(Levelorder Traversal)二叉树,是指从二叉树的第一层(根结点)开始,自上至下逐层遍历,在同一层中,则按从左到右的顺序对结点逐个访问。对于右图所示的二叉树,按层序遍历方式进行遍历所得到的结点序列为:A、B、C、D、E、F、G、H、I。
3. 二叉树的存储结构
3.1 数组表示法
二叉树的数组表示就是采用一组连续存储空间存储二叉树结点中的数据元素,利用数组下标来反映数据元素之间的关系。
对具有n个结点的完全二叉树按从上到下、自左向右的顺序连续给结点编号0、1、2、…、n-1。按此结点编号将二叉树中各结点中的数据元素顺序地存放于一个一维数组中,首先将根结点中的数据元素储存在数组的0号位置;对于二叉树中任一个结点,如果它的数据元素存储在数组的第i个位置,就把它的左、右孩子结点中的数据元素分别存放在数组的第2i+1个位置和第2i+2个位置。这样就得到了二叉树的一种数组表示法。
采用这种方法表示一般的二叉树时,空间利用效率低是一个主要的问题。当被表示的二叉树结构很不完整时,在数组中就会出现很多空位置,因此空间浪费就变得非常大。
用这种方法表示二叉树时,还有一个问题需要注意的是:必须处理结点不存在的情况。如果一个结点不存在,就必须在数组中相应位置设置一个特殊标志,指明在这个位置没有结点。
二叉树的二叉链表表示,对于大多数的应用来说是适合的。但是,在二叉链表中要想找出一个结点的双亲是比较困难的,必须通过二叉树的遍历才能实现。如果在应用中需要方便地找到任何一个结点的双亲,可以在结点中增加一个Parent域来指向该结点的双亲,二叉树的这种表示方法称为三叉链表。
3.2 链表表示法
在二叉树的链表表示中,树中的每一个元素用一个结点表示,结点一般包括三个域,其结构如图(a)所示。其中,Data域用于存放数据元素的信息;leftChild域用于存放指向其左孩子结点的指针;rightChild域用于存放指向其右孩子结点的指针。二叉树的这种链表表示称为二叉链表。
4. 二叉树实现
中序遍历是有序的二叉树(不重复)
|
|