二叉查找树
来源:互联网 发布:音频剪辑 for mac 编辑:程序博客网 时间:2024/05/18 02:58
二叉查找树
先说一下什么是二叉查找树,它是一种特殊的二叉树,其递归定义如下:
- 左子树任意节点值小于根节点,右子树任意节点值大于根节点
- 任意节点的左子树和右子树也是二叉查找树
- 任意节点的值不同
二叉查找树的功能主要有三点:
- 插入
- 删除
- 查询
但因为使用二叉查找树进行上述操作,所用时间和树的深度成正比,因此若有N个元素,操作的平均时间复杂度为O(logN),是一种极为高效的数据结构。
二叉查找树如何实现呢?我们先逐一分析。
查询
假设我们要查询数字X,我们先让X和根节点比,如果X小,则X在根节点的左子树中,反之在根节点的右子树中,然后继续按照上述规则与子树的根节点相比较,直到匹配成功。
插入
插入和查询类似,也是先和根节点比较,小就放左边,大就放右边,直到存在空节点并且满足构成的树是二叉查找树。
删除
删除较为复杂,因为一旦把中间某个节点删除,其子树便悬空了,那么我们如何处理这种情况呢?我们首先想到,能不能把子树的某一个节点提到该节点处,使之成为新的二叉查找树呢?这种想法是可行的,不过要遵从我们的目的:使之成为一棵新的二叉查找树。下面直接给出三个处理步骤:
- 如果删除节点没有左儿子,则直接把右儿子提上去。
- 如果删除节点左儿子没有右儿子,则把左儿子提上去。
- 如果不满足上两种情况,则把左儿子子孙中最大的提上去。
那么如何用代码实现呢?
我们使用结构体来表征每一个节点(每个节点拥有数据值以及指向左右儿子的指针)。
typedef struct BST{ int data; struct BST *left,*right;}node;
根据上述分析,插入元素代码如下:
node *insertData(node *ptr,int data){ if(ptr == NULL){ //空节点则构造新节点并返回 node *temp; temp = (node *)malloc(sizeof(node)); temp->data = data; temp->left = NULL; //将左右子树置空,预留位置 temp->right = NULL; return temp; } else{ if(data < ptr->data) //如果小于,放在左子树 ptr->left = insertData(ptr->left,data); else //如果大于,放在右子树 ptr->right = insertData(ptr->right,data); return ptr; }}
查询代码如下:
int findData(node *ptr,int data) //返回1表示存在,返回0表示不存在{ if(ptr == NULL) //如果空,表示没找到,返回0 return 0; else if(ptr->data == data) //找到,返回1 return 1; else if(data < ptr->data) //如果小于当前节点值,则从左子树继续找 return findData(ptr->left,data); else //如果大于,则从右子树继续找 return findData(ptr->right,data);}
删除代码如下:
node *deleteData(node *ptr,int data) //在ptr指向节点的子树及自己中删除data{ if(ptr == NULL) //如果空节点,则返回NULL return NULL; else if(data < ptr->data) //如果小于,则从左子树继续进行 ptr->left = deleteData(ptr->left,data); else if(data > ptr->data) //如果大于,则从右子树继续进行 ptr->right = deleteData(ptr->right,data); else if(ptr->left == NULL){ //如果没有左子树,则把右子树提上去 node *temp = ptr->right; free(ptr); return temp; } else if(ptr->left->right == NULL){ //如果左儿子没有右儿子,把左儿子提上去 node *temp = ptr->left; temp->right = ptr->right; free(ptr); return temp; } else{ //否则把左儿子最大子孙提上去 node *temp; for(temp = ptr->left;temp->right->right != NULL;temp = temp->right) ;// 找到最大子孙的父亲 node *temp2 = temp->right; //temp2为最大子孙 temp->right = temp2->left; //最大子孙的父亲接过右儿子的左儿子 temp2->left = ptr->left; //最大子孙成功提上去,取代ptr temp2->right = ptr->right; free(ptr) ; return temp2; } return ptr;}
现在我们来测试一下,测试代码如下:
#include <iostream>#include <stdlib.h>#include <stdio.h>using namespace std; typedef struct BST{ int data; struct BST *left,*right;}node;void print(node *root) //中序遍历 { if(root){ cout<<root->data<<" "; print(root->left); print(root->right); }}node *insertData(node *ptr,int data){ if(ptr == NULL){ //空节点则构造新节点并返回 node *temp; temp = (node *)malloc(sizeof(node)); temp->data = data; temp->left = NULL; //将左右子树置空,预留位置 temp->right = NULL; return temp; } else{ if(data < ptr->data) //如果小于,放在左子树 ptr->left = insertData(ptr->left,data); else //如果大于,放在右子树 ptr->right = insertData(ptr->right,data); return ptr; }}int findData(node *ptr,int data) //返回1表示存在,返回0表示不存在{ if(ptr == NULL) //如果空,表示没找到,返回0 return 0; else if(ptr->data == data) //找到,返回1 return 1; else if(data < ptr->data) //如果小于当前节点值,则从左子树继续找 return findData(ptr->left,data); else //如果大于,则从右子树继续找 return findData(ptr->right,data);}node *deleteData(node *ptr,int data) //在ptr指向节点的子树及自己中删除data{ if(ptr == NULL) //如果空节点,则返回NULL return NULL; else if(data < ptr->data) //如果小于,则从左子树继续进行 ptr->left = deleteData(ptr->left,data); else if(data > ptr->data) //如果大于,则从右子树继续进行 ptr->right = deleteData(ptr->right,data); else if(ptr->left == NULL){ //如果没有左子树,则把右子树提上去 node *temp = ptr->right; free(ptr); return temp; } else if(ptr->left->right == NULL){ //如果左儿子没有右儿子,把左儿子提上去 node *temp = ptr->left; temp->right = ptr->right; free(ptr); return temp; } else{ //否则把左儿子最大子孙提上去 node *temp; for(temp = ptr->left;temp->right->right != NULL;temp = temp->right) ;// 找到最大子孙的父亲 node *temp2 = temp->right; //temp2为最大子孙 temp->right = temp2->left; //最大子孙的父亲接过右儿子的左儿子 temp2->left = ptr->left; //最大子孙成功提上去,取代ptr temp2->right = ptr->right; free(ptr) ; return temp2; } return ptr;}int main(void){ node *root; root = (node *)malloc(sizeof(node)); root = NULL; root = insertData(root,8); root = insertData(root,3); root = insertData(root,10); root = insertData(root,1); root = insertData(root,6); root = insertData(root,14); root = insertData(root,4); root = insertData(root,7); root = insertData(root,13); //插入数据 print(root); cout<<"\n"; cout<<findData(root,20)<<"\n"; cout<<findData(root,10)<<"\n"; //查找数据 deleteData(root,10); //删除数据 print(root); cout<<"\n"; return 0;}
ouput:
8 3 1 6 4 7 10 14 13
0
1
8 3 1 6 4 7 14 13
- 查找--二叉查找树
- 二叉树、二叉查找树
- 二叉树 & 二叉查找树
- 【查找结构】二叉查找树
- 查找之二叉树查找
- 查找之二叉树查找
- 查找:二叉查找树总结
- 二叉树查找树...
- 二叉树查找树
- 查找--遍历二叉树
- 二叉查找树
- 二叉查找树实现
- 二叉查找树
- 动态二叉查找树
- 最优二叉查找树
- 二叉查找树
- 二叉查找树
- 平衡二叉查找树
- xib上控件不显示,或者为nil
- LINQ to DataSet的DataTable操作
- Cocos、Lua游戏内存释放之我见
- 1. 用U盘安装Centos6.5 + Win7 双系统
- 在storyboard中点击控件,右边状态栏显示 No Applicable
- 二叉查找树
- 关于ZIGBEE端点的一点理解
- Socket深入学习
- RTLinux 和 Xenomai 系统在mini2440的移植——usb无线网卡死机问题
- 修改Ubuntu16.04文件数、进程数限制!
- CentOS6.7 下搭建 Hadoop2.7.1 单机伪分布式环境
- 贪心算法-泊松分酒问题
- iOS对象内存结构中的 isa 指针是用来做什么的?
- js中for语句