第39节 二叉排序树

本文深入解析二分查找与二叉排序树的特性与应用,包括二分查找的时间复杂度、适用场景,以及二叉排序树的定义、插入、删除操作和创建过程,强调了数据结构在提高查找效率方面的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

-------------------------------------资源来源于网络,仅供自学使用,如有侵权,联系我必删.

第一:

二分查找的回顾

二分查找的特点
   二分查找能够提高有序表中数据元素的查找速度
  二分查找的时间复杂度为O(log2n)
  二分查找是一种静态查找
二分查找的不足
  当查找表经常变化时 当查找表经常变化时,二分查找的整体性能急剧下降

 

第二:

二叉排序树

二叉排序树的定义
二叉排序树是一棵空树,或者  
• 若它的左子树不空,则左子树上所有结点的值均小于它的 ,则左子树上所有结点的值均小于它的根结点的值
• 若它的右子树不空,则右子树上所有结点的值均大于它的 ,则右子树上所有结点的值均大于它的根结点的值
• 它的左右子树也分别是二叉排序树

 

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

二叉排序树是特殊的二叉树,因此具有与二叉树相同的操作 ,因此具有与二叉树相同的操作!

 

二叉排序树的插入和删除操作
插入:
• 其插入操作总是在叶结点处进行
删除:
• 叶结点:直接删除 :直接删除
• 非叶结点:查找合适的替代者后删除 :查找合适的替代者后删除
二叉排序树的所有操作都必须保证其二叉排序性不变!

 

如何为删除操作查找合适的替代者
有一个孩子的结点:
• 用孩子结点代替原结点
有两个孩子的结点:
• 用中序遍历下的直接前驱替换原结点

 

二叉排序树的创建

基于BSTree.h 和 BSTree.c

#include <stdio.h>
#include <stdlib.h>
#include "BSTree.h"

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

struct Node
{
    BSTreeNode header;
    char v;
};

void printf_data(BSTreeNode* node)
{
    if( node != NULL )
    {
        printf("%c", ((struct Node*)node)->v);
    }
}

int compare_key(BSKey* k1, BSKey* k2)
{
    return (int)k1 - (int)k2;
}

int main(int argc, char *argv[])
{
    BSTree* tree = BSTree_Create();
    
    struct Node n1 = {{(BSKey*)1, NULL, NULL}, 'A'};
    struct Node n2 = {{(BSKey*)2, NULL, NULL}, 'B'};
    struct Node n3 = {{(BSKey*)3, NULL, NULL}, 'C'};
    struct Node n4 = {{(BSKey*)4, NULL, NULL}, 'D'};
    struct Node n5 = {{(BSKey*)5, NULL, NULL}, 'E'};
    struct Node n6 = {{(BSKey*)6, NULL, NULL}, 'F'};
    
    BSTree_Insert(tree, (BSTreeNode*)&n4, compare_key);
    BSTree_Insert(tree, (BSTreeNode*)&n1, compare_key);
    BSTree_Insert(tree, (BSTreeNode*)&n3, compare_key);
    BSTree_Insert(tree, (BSTreeNode*)&n6, compare_key);
    BSTree_Insert(tree, (BSTreeNode*)&n2, compare_key);
    BSTree_Insert(tree, (BSTreeNode*)&n5, compare_key);
    
    printf("Height: %d\n", BSTree_Height(tree));
    printf("Degree: %d\n", BSTree_Degree(tree));
    printf("Count: %d\n", BSTree_Count(tree));
    printf("Search Key 5: %c\n", ((struct Node*)BSTree_Get(tree, (BSKey*)5, compare_key))->v);
    printf("Full Tree: \n");
    
    BSTree_Display(tree, printf_data, 4, '-');
    
    BSTree_Delete(tree, (BSKey*)4, compare_key);
    
    printf("After Delete Key 4: \n");
    printf("Height: %d\n", BSTree_Height(tree));
    printf("Degree: %d\n", BSTree_Degree(tree));
    printf("Count: %d\n", BSTree_Count(tree));
    printf("Full Tree: \n");
    
    BSTree_Display(tree, printf_data, 4, '-');
    
    BSTree_Clear(tree);
    
    printf("After Clear: \n");
    printf("Height: %d\n", BSTree_Height(tree));
    printf("Degree: %d\n", BSTree_Degree(tree));
    printf("Count: %d\n", BSTree_Count(tree));
    
    BSTree_Display(tree, printf_data, 4, '-');
    
    BSTree_Destroy(tree);
    
	return 0;
}

 

小结
二分查找仅适用于静态查找的情形
二叉排序树是从二分查找的过程总结而来的一种数据结构
二叉排序树的查找效率和二分查找相同
二叉排序树是特殊的二叉树其插入和删除操作必须保证其二叉排序的性质不变

### 构建二叉排序树的过程 根据给定的关键字序列 `(4, 9, 0, 1, 8, 6, 3, 5, 2, 7)` 创建一棵二叉排序树 `bt` 的过程如下: #### 插入点的原则 对于每一个新插入的点,遵循以下原则: - 如果当前点值小于根点值,则将其插入到左子树; - 如果当前点值大于等于根点值,则将其插入到右子树。 此规则适用于每一次插入操作,直到所有关键字都被成功插入为止[^3]。 --- #### 步骤描述(不使用步骤词汇) 初始状态:空树 第一次插入:将 `4` 设为根点。此时树的状态为 `(4)`。 第二次插入:`9 > 4`,因此将 `9` 插入到 `4` 的右子树中。树变为 `(4(,)(9))`。 第三次插入:`0 < 4`,因此将 `0` 插入到 `4` 的左子树中。树变为 `(4(0)(9))`。 第四次插入:`1 < 4` 且 `1 > 0`,因此将 `1` 插入到 `0` 的右子树中。树变为 `(4(0()(1))(9))`。 第五次插入:`8 < 9` 且 `8 > 4`,因此将 `8` 插入到 `4` 和 `9` 中间的位置作为右子树的一部分。树变为 `(4(0()(1))(9(8)))`。 第六次插入:`6 < 9` 且 `6 > 4`,进一步比较发现 `6 < 8`,所以将 `6` 插入到 `8` 的左子树中。树变为 `(4(0()(1))(9(8(6))))`。 第七次插入:`3 < 4` 且 `3 > 0`,进一步比较发现 `3 < 1`,所以将 `3` 插入到 `1` 的左子树中。树变为 `(4(0()(1(3)))(9(8(6))))`。 第八次插入:`5 < 9` 且 `5 > 4`,进一步比较发现 `5 < 8` 且 `5 > 6`,所以将 `5` 插入到 `6` 的右子树中。树变为 `(4(0()(1(3)))(9(8(6()(5)))))`。 第九次插入:`2 < 4` 且 `2 > 0`,进一步比较发现 `2 < 1`,所以将 `2` 插入到 `3` 的右子树中。树变为 `(4(0()(1(3(2))))(9(8(6()(5)))))`。 第十次插入:`7 < 9` 且 `7 > 4`,进一步比较发现 `7 < 8` 且 `7 > 6`,所以将 `7` 插入到 `6` 的右子树中。最终树变为 `(4(0()(1(3(2))))(9(8(6()(5))(7))))`。 --- ### 输出结果 按照括号表示法,最终生成的二叉排序树为: ```plaintext (4(0()(1(3(2))))(9(8(6()(5))(7)))) ``` --- ### 验证是否为二叉排序树 验证方法是对该二叉树进行 **中序遍历**,检查其结果是否为递增有序序列。如果满足条件,则证明该树是一棵合法的二叉排序树[^1]。 对上述树执行中序遍历时得到的序列为 `[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]`,这是一个严格递增的序列,因此可以确认这棵树确实是一棵二叉排序树。 --- ### Python 实现代码 以下是基于上述逻辑的 Python 实现代码: ```python class TreeNode: def __init__(self, key): self.left = None self.right = None self.val = key def insert(root, key): if root is None: return TreeNode(key) if key < root.val: root.left = insert(root.left, key) elif key >= root.val: root.right = insert(root.right, key) return root def inorder_traversal(root, result=None): if result is None: result = [] if root: inorder_traversal(root.left, result) result.append(root.val) inorder_traversal(root.right, result) return result def build_bst_from_sequence(sequence): root = None for key in sequence: root = insert(root, key) return root def tree_to_parentheses_notation(root): if not root: return "" left_str = tree_to_parentheses_notation(root.left) right_str = tree_to_parentheses_notation(root.right) return f"({root.val}{left_str}{right_str})" # 测试部分 sequence = [4, 9, 0, 1, 8, 6, 3, 5, 2, 7] bst_root = build_bst_from_sequence(sequence) parentheses_representation = tree_to_parentheses_notation(bst_root) print(parentheses_representation) # 输出 (4(0()(1(3(2))))(9(8(6()(5))(7)))) inorder_result = inorder_traversal(bst_root) print(inorder_result) # 输出 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值