持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第23天,点击查看活动详情
二叉排序树
顾名思义,二叉排序树可以用于排序,也可以用于查找(或者称检索)。利用二叉排序树可以大大提高查找的时间效率,因此,二叉排序树也称为二叉查找树。
二叉排序树的定义
二叉排序树(binary sort tree)是一棵二叉树,若根结点的左子树不空,则左子树中所有结点的值均小于根结点的值;若根结点的右子树不空,则右子树中所有结点的值均大于或者等于根结点的值。每一棵子树也同样具有上述特性,即二叉排序树中的任何一棵子树也是一棵二叉排序树。
二叉排序树的建立(插入)
通常采用逐点插人结点的方法来构造二叉排序树。现将逐点插入法表述如下:
此插入法的表述存在一个疑问,就是,新节点插在某个叶节点的下面,成为一个新的叶节点。一定要插在叶节点下面吗?比如插在一个有左子树无右节点的节点。如下图,在10节点的右侧插入20.
很容易想到,对于给定的一个数据元素序列,若元素插入到二叉树的次序不同,则所建立的二叉排序树的形式也就不同。下面给出建立二叉排序树的非递归算法(设二叉排序树采用二叉链表存储结构)。
BTREE SORTTREE(datatype K[], int n) {
void INSERTBST(BTREE *T, datatype item);
BTREE T = NULL;
if (n > 0) {
for (int i = 0; i < n; ++i) {
INSERTBST(&T, K[i]);
}
}
return T;
}
void INSERTBST(BTREE *T, datatype item) {
BTREE p, q;
p = (BTREE) malloc(sizeof(BTNode));
p->data = item;
p->lchild = NULL;
p->rchild = NULL;
if ((*T) == NULL)
*T = p;
else {
q = (*T);
while (1) {
if (item < q->data) {
if (q->lchild != NULL)
q = q->lchild;
else {
q->lchild = p;
break;
}
} else {
if (q->rchild != NULL)
q = q->rchild;
else {
q->rchild = p;
break;
}
}
}
}
}
递归算法:
//递归算法
void INSERTBST1(BTREE *T, datatype item) {
if ((*T) == NULL) {
(*T) = (BTREE) malloc(sizeof(BTNode));
(*T)->data = item;
(*T)->lchild = NULL;
(*T)->rchild = NULL;
} else if (item < (*T)->data)
INSERTBST1(&((*T)->lchild), item);
else
INSERTBST1(&((*T)->rchild), item);
}
按照二叉排序树的定义,在上述插入算法中,值相同的数据元素插入到结点的右子树中。可以设想,如果这样的数据元素越多,二叉树的深度会变得越大,在后面的讨论中可以看到,这将会降低查找操作的效率。一个解决的方法是适当增加二叉树的存储空间开销,即在链结点中增加一个域以指示相同元素发生的频率。当然,如果数据元素集合只是一个更大结构的一部分,则该方法也有问题。此时可以把相同数据元素保留在一个辅助数据结构中,例如一个表或者另一棵二叉排序树中。
有趣的是,数据元素序列K一般不一定是一个按值排序的序列,但将其构造为一棵二叉排序树以后,对该二叉排序树进行中序遍历,得到的中序遍历序列却是一个按值排序的序列。这就是说,一个元素序列可以通过构造二叉排序树,然后对二叉排序树进行中序遍历而转化为一个有序序列。