2.4树的应用——二叉搜索树
2.4.1二叉搜索树(Binary Search Tree)的定义与性质
也称为二叉排序树或者二叉搜索树
性质:
- 非空左子树的所有键值小于其根结点的键值
- 非空右子树的所有键值大于其根结点的键值
- 左、右子树都是二叉搜索树
2.4.2二叉搜索树的查找
1 typedef struct TreeNode* BinTree; 2 struct TreeNode { 3 int data; 4 BinTree left; 5 BinTree right; 6 }; 7 8 //递归查找 查找元素x 9 BinTree Find(int x, BinTree BST) { 10 if(BST) { 11 if (x < BST->data) 12 return Find(x, BST->left); 13 else if (x > BST->data) 14 return Find(x, BST->right); 15 else 16 return BST; 17 } 18 return 0; 19 } 20 //非递归查找,将尾递归函数转化为迭代函数 21 BinTree InterFind(int x, BinTree BST) { 22 if (BST) { 23 if (x < BST->data) 24 BST = BST->left; 25 else if (x > BST->data) 26 BST = BST->right; 27 else 28 return BST; 29 } 30 return 0; 31 }
归纳:查找的效率取决于树的高度
查找最大/最小元素:最大元素一定在树的最右边;最小元素一定在树的最左边。
1 //查找最小元素的递归函数 2 BinTree FindMin(BinTree BST) { 3 if (BST) { 4 if (!BST->left) 5 return BST; 6 else 7 return FindMin(BST->left); 8 } 9 return NULL; 10 } 11 //查找最大元素的迭代函数 12 BinTree FinfMax(BinTree BST) { 13 if (BST) { 14 while (BST->right) 15 BST = BST->right; 16 return BST; 17 } 18 return NULL; 19 }
2.4.3二叉搜索树的插入
关键是要找到元素应该插入的位置,但是和Find函数不同的是每次要记住插入结点所在子树的根结点,通过递归的方法把下一层的结构返回,然后连接在一起
1 BinTree Insert(int x, BinTree BST) { 2 if (!BST) {//如果树为空 3 BST = (BinTree)malloc(sizeof(TreeNode)); 4 BST->data = x; 5 BST->left = NULL; 6 BST->right = NULL; 7 } 8 else { 9 if (x < BST->data) 10 BST->left = Insert(x, BST->left);//在左子树中插入,并且将根结点指向被改变的左子树 11 else 12 BST->right = Insert(x, BST->right); 13 } 14 return BST;//返回的是根结点 15 }
2.4.4二叉搜索树的删除
考虑三种情况:
- 要删除的是叶结点:直接删除,并修改其父结点指针——置为NULL;
- 要删除的结点只有一个孩子结点:将其父结点的指针指向要删除结点的孩子结点,即其孙子结点;
- 要删除的结点有左、右两棵树:用另一个结点替代被删除结点,即右子树的最小元素或者左子树的最大元素。其实就是转化成前两种情况,因为最小(最大)元素,一定在最左(最右),一定是叶结点或者只有一个孩子的结点。
1 BinTree Delete(int x, BinTree BST) { 2 BinTree tmp; 3 //如果是空树 4 if (!BST)cout << "要删除的元素未找到"; 5 //如果没找到待删除结点 6 else if (x < BST->data) 7 //将左子树删除之后的新的根结点挂在左边 8 BST->left = Delete(x, BST->left); 9 else if (x > BST->data) 10 BST->right = Delete(x, BST->right); 11 //如果找到待删除结点 12 else { 13 //如果待删除结点有两个孩子 14 if (BST->left&&BST->right) { 15 tmp = FindMin(BST->right); 16 BST->data = tmp->data;//将右子树的最小值的元素覆盖待删除结点 17 BST->right = Delete(tmp->data, BST->right);//删除替代待删除结点的右子树最小值 18 } 19 //如果有一个还是或者没有孩子 20 else { 21 tmp = BST;//直接删除待删除结点 22 //如果没有右孩子,意味着只有左孩子或者没有孩子 23 if (!BST->right) 24 BST = BST->left; 25 //如果没有左孩子 26 else if (!BST->left) 27 BST = BST->right; 28 free(tmp); 29 } 30 } 31 return BST; 32 }