实验十三 二叉排序树
一、 实验目的
(1) 掌握建立二叉排序树的方法;
(2) 掌握二叉排序树结点的查找方法;
(3) 了解二叉排序树结点的删除方法。
二、 实验环境
Windows 7以上版本的操作系统,Visual Studio 2010版以上编程环境。
三、 实验内容和步骤
1. 已知序列{36,20,50,80,30,10,26,56},
1)画出用上面的数据创建二叉排序树的过程;
二叉排序树的过程如下:
2) 写出它的中序遍历结果;
中序遍历结果:10,20,26,30,36,50,56,80
3) 写出在这棵二叉排序树中查找数据70和30的过程及结果;
查找数据70: 先从根开始与36比较,大于36,走向右子树与50比较,大于50,走向右子树与80比较,小于80,走向左子树与56比较,大于56,走向右子树,右子树为空,查找失败;
查找数据30:先从根开始与36比较,小于36,走向左子树与20比较,大于20,走向右子树与30比较,与相等30,查找成功。
4) 运行BiTree项目,验证二叉排序树的建立和查找过程。
二叉排序树的建立和查找过程:
5) 参考课本P325的InsertBST函数,把BiTree.cpp中的BSTInsert函数改为用递归算法实现。
BSTInsert函数递归算法实现:
bool BSTInsert(BTNode *&root, ElemType item)
{
if (root == NULL) //空树,item成为根
{
root = new BTNode;
root->data = item;
root->left = NULL;
root->right = NULL;
return true;
}
else if (item == root->data)//存在相同关键字,无需插入
return false;
else if (item < root->data) //插入到左子树中
return BSTInsert(root->left, item);
else //插入到右子树中
return BSTInsert(root->right, item);
}
- 在二叉排序树中分别删除26、50、20、36,并画出删除后的二叉排序树。
删除后的二叉排序树:
- 运行BiTree项目,验证二叉排序树的删除过程。
删除过程验证:
2. (选做)
在BiTree项目中,结点删除函数BSTDelete在删除双分支结点时,是使用被删除双分支结点的中序前驱的值代替被删除双分支结点的值,然后把中序前驱删掉。
尝试用另一种方法改写BSTDelete函数:在删除双分支结点时,使用双分支结点的中序后继的值代替被删除双分支结点的值,再把中序后继删掉。
对于修改后的双分支结点的删除操作程序如下:
//删除二叉排序树中与指定的数据相同的结点
bool BSTDelete(BTNode *&root, ElemType item)
{
BTNode *p = root, *q = NULL; //q指向p的父结点
//查找与item相等的结点p
while (p != NULL) {
if (item == p->data)
break; //找到需要删除的结点
q = p;
if (item < p->data)
p = p->left; //在左子树中查找
else
p = p->right; //在右子树中查找
}
//与item相同的结点不存在
if (p == NULL) {
cout << "删除失败" << endl;
return false; //树中找不到item,删除失败
}
//p指向找到的item结点,进行删除,需要调整二叉树
//p是叶子结点
if (p->left == NULL && p->right == NULL) {
//q是p的父结点
if (p == root) //删除结点为树根
root = NULL;
else if (q->left == p) //p是其父结点的左子结点
q->left = NULL;
else
q->right = NULL;
}
//p是单分支结点
else if (p->left == NULL || p->right == NULL) {
BTNode *subtree; //指向p的子树
if (p->left == NULL)
subtree = p->right;
else
subtree = p->left;
if (p == root) //删除结点为树根
root = subtree;
else if (q->left == p) //p是其父结点的左子结点
q->left = subtree;
else
q->right = subtree;
}
//p是双分支结点
else {
BTNode *twobranch = p; //记下双分支结点的位置
p = twobranch->right; //在双分支结点的左子树中寻找中序后继
while (p->left != NULL) {
q = p; //q为p的父结点
p = p->left; //右子树的最左结点即中序后继
}
//此时p指向中序后继
twobranch->data = p->data; //用中序后继的值代替双分支结点的值
//需要删除中序后继
//中序后继没有左子树,在删除中序后继之前保存其右子树
if (p == twobranch->right) //特殊情况:如果中序后继就是双分支结点的右子树的根
twobranch->right = p->right;
else //一般情况
q->left = p->right;
}
//删除结点并释放内存
delete p;
return true;
}
3. 思考:当关键字相同,但出现的顺序不同时,按照二叉排序树的创建方法,将创建出形态不同的二叉排序树。例如以下的关键字序列和对应的二叉排序树:
a) 比较以上两颗二叉排序树,哪一颗更有利于进行关键字的查找?
答:左边的二叉排序树更利于进行关键字的查找,因为左边的二叉排序树相比右边的排序树,平均查找长度ASL更加低。
b) 知识点扩展:平衡二叉树(课本P333)