二叉查找树

来源:互联网 发布:音频剪辑 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


0 0