二叉搜索树入门指南:高效查找的数据结构实现
一、简介和应用
二叉搜索树(Binary Search Tree, BST)是一种特殊的二叉树数据结构,其中每个节点的值大于其左子树所有节点的值,小于其右子树所有节点的值。这种特性使得BST在查找、插入和删除操作上具有很高的效率。
应用场景:
数据库索引实现
文件系统目录管理
字典和电话簿实现
游戏中的高分排行榜
网络路由表
内存分配管理
BST的平均时间复杂度为O(log n),在数据有序性要求高且需要频繁查找的场景中表现优异。
二、特点和注意事项
特点:
注意事项:
三、实现步骤解析
定义节点结构:创建包含数据、左指针和右指针的结构体
初始化BST:创建根节点并维护节点计数器
实现核心操作:
插入节点:递归找到合适位置插入新节点
查找节点:利用BST特性快速定位
删除节点:处理三种情况(无子节点、单子节点、双子节点)
辅助功能:
查找前驱节点:用于删除操作
查找最小值:用于删除双子节点情况
实现遍历:
前序遍历:根-左-右顺序
中序遍历:左-根-右顺序(得到有序序列)
四、完整代码和注释
#include<iostream> using namespace std; // 定义二叉搜索树节点结构 struct treenode{ int data=0; // 节点存储的数据,默认为0 treenode* left=nullptr; // 左子节点指针,默认为空 treenode* right=nullptr; // 右子节点指针,默认为空 }; // 定义二叉搜索树类 class binaryfindtree{ treenode* root=new treenode; // 根节点 int sum = 0; // 节点计数器 // 内部递归插入方法 void add(int data, treenode* root){ if (sum==0){ // 如果是第一个节点 root->data = data; // 直接赋值给根节点 }else{ if(data<root->data){ // 如果数据小于当前节点 if(root->left) // 如果左子节点存在 add(data, root->left); // 递归向左子树插入 else { // 如果左子节点不存在 root->left = new treenode; // 创建新节点 root->left->data = data; // 赋值 } }else{ // 如果数据大于等于当前节点 if(root->right) // 如果右子节点存在 add(data, root->right); // 递归向右子树插入 else { // 如果右子节点不存在 root->right = new treenode; // 创建新节点 root->right->data = data; // 赋值 } } } sum++; // 节点计数增加 } // 内部递归查找方法 treenode* get(int data, treenode* root){ if (!root) // 如果节点为空 return nullptr; // 返回空指针 if (root->data == data) // 如果找到数据 return root; // 返回当前节点 if (data < root->data) // 如果数据小于当前节点 return get(data, root->left); // 递归左子树查找 else // 如果数据大于当前节点 return get(data, root->right); // 递归右子树查找 } // 查找指定节点的父节点 treenode* getpre(int data, treenode* root) { if (!root) // 如果节点为空 return nullptr; // 返回空指针 if (!root->left and !root->right) // 如果是叶子节点 return nullptr; // 返回空指针 // 检查左子节点 if (!root->left){ // 如果没有左子节点 if (root->right->data == data) // 如果右子节点匹配 return root; // 返回当前节点(父节点) }else{ if (!root->right){ // 如果没有右子节点 if (root->left->data == data) // 如果左子节点匹配 return root; // 返回当前节点(父节点) }else{ // 如果有两个子节点 if (root->left->data == data or root->right->data == data) // 如果任一子节点匹配 return root; // 返回当前节点(父节点) } } // 递归查找左右子树 if (getpre(data, root->left)) // 先在左子树查找 return getpre(data, root->left); else // 再在右子树查找 return getpre(data, root->right); } // 查找子树中的最小节点 treenode* mindata(treenode* root) { if (!root->left) // 如果没有左子节点 return root; // 当前节点就是最小节点 return mindata(root->left); // 递归查找左子树 } // 内部递归删除方法 treenode* del(int data, treenode* root){ if (!root or (!root->left and !root->right)) // 空树或只有根节点 return nullptr; treenode* tmp = get(data, root); // 找到要删除的节点 treenode* pre = getpre(data, root); // 找到父节点 bool lr = pre->right == tmp; // 判断是左子节点还是右子节点 // 情况1: 要删除的节点是叶子节点 if (!tmp->left and !tmp->right){ !lr ? pre->left = nullptr : pre->right = nullptr; // 父节点对应指针置空 return root; } // 情况2: 要删除的节点只有一个子节点 if (!tmp->right) // 只有左子节点 !lr ? pre->left = tmp->left : pre->right = tmp->left; // 用左子节点替代 else{ if (!tmp->left) // 只有右子节点 !lr ? pre->left = tmp->right : pre->right = tmp->right; // 用右子节点替代 else{ // 情况3: 有两个子节点 tmp->data = mindata(root->right)->data; // 用右子树最小节点值替换 tmp->right = del(tmp->data, mindata(root->right)); // 删除右子树最小节点 } } sum--; // 节点计数减少 return root; } // 前序遍历(根-左-右) void preorder(treenode* root) { if (!root) // 如果节点为空 return; // 返回 cout << root->data << " "; // 先访问根节点 preorder(root->left); // 再遍历左子树 preorder(root->right); // 最后遍历右子树 } // 中序遍历(左-根-右) void inorder(treenode* root){ if (!root) // 如果节点为空 return; // 返回 inorder(root->left); // 先遍历左子树 cout << root->data << " "; // 再访问根节点 inorder(root->right); // 最后遍历右子树 } public: // 公开插入接口 void add(int data){ add(data, root); } // 查找接口 bool find(int data){ return get(data, root) != nullptr; // 转换为bool值返回 } // 删除接口 void del(int data){ root = del(data, root); } // 中序遍历接口 void inorder(){ inorder(root); cout << endl; } // 前序遍历接口 void preorder() { preorder(root); cout << endl; } };
五、总结
二叉搜索树是一种高效的数据结构,特别适合需要频繁查找、插入和删除操作的场景。本文通过完整的C++实现,展示了BST的核心操作和两种遍历方式。理解BST的工作原理对于学习更高级的数据结构(如AVL树、红黑树等)至关重要。在实际应用中,需要注意保持树的平衡以获得最佳性能。
链接:二叉搜索树
原创内容 转载请注明出处