二叉查找树的基本操作实现

二叉查找树又叫二叉排序树,其特点有:

  1. 对于每一棵子树,若左子树不为NULL,则左子树所有节点都小于它的根结点值。
  2. 对于每一棵子树,若右子树不为NULL,则左子树所有节点都大于它的根结点值。
  3. 没有键值相等的结点。

完成二叉查找树的基本操作有:

  1. 插入结点。
  2. 查找结点。
  3. 查找最小关键字:根据二叉查找树的特点,应该是最左边的结点
  4. 查找最大关键字:根据二叉查找树的特点,应该是最右边的结点
  5. 删除结点。

以上操作中,难点在与插入和删除。分别说下其主要思想:

插入:根据插入数据与结点的比较,找寻它的插入位置,若比结点值大,则往结点的右子树继续寻找,直到其右孩子为空,将新结点作为其右孩子;若比结点值小,则往结点的左子树继续寻找,直到其左孩子为空,将新结点作为其左孩子。

删除:设要查找的结点为d

  1. 若d有左子树,则用d的左孩子取代它,找到其左子树的最右边的结点r,把f的右孩子作为r的右子树。
  2. 若d无左子树,则直接用它的右孩子取代它。

但执行删除操作时要注意要删除的结点是否是几个特殊的结点:空结点、根结点、叶子节点。

代码示例:

//插入结点
//查找元素
//查找最小关键字
//查找最大关键字
//删除节点
#include <stdio.h>
#include <stdlib.h>
typedef struct Node
{
    int data;
    struct Node* lchild;
    struct Node* rchild;
    struct Node* parent;
}Node;
//往二叉查找树中插入结点  
//插入的话,可能要改变根结点的地址,所以传的是二级指针  
void insert_node(Node** root,int _data)
{
    Node* newnode=(Node*)malloc(1*sizeof(Node));
    newnode->data=_data;
    newnode->lchild=NULL;
    newnode->rchild=NULL;
    newnode->parent=NULL;
    if(*root==NULL)
    {
        *root=newnode;
        return ;
    }
    if((*root)->lchild==NULL && _data < (*root)->data)
    {
        (*root)->lchild=newnode;
        newnode->parent=*root;
        return ;
    }
    if((*root)->rchild==NULL && _data > (*root)->data)
    {
        (*root)->rchild=newnode;
        newnode->parent=*root;
        return ;
    }
    if( _data < (*root)->data )
    {
        insert_node(&(*root)->lchild,_data);
    }
    else
    {
        if( _data > (*root)->data)
        {
            insert_node(&(*root)->rchild,_data);
        }
        else
        {
            return ;
        }
    }
}
//输出节点元素
void print_tree(Node* root)
{
    if(root==NULL)
        return ;
    printf("%d\t",root->data);
    print_tree(root->lchild);
    print_tree(root->rchild);
}
//查找元素,找到返回关键字的结点指针,没找到返回NULL  
Node* find_node(Node* root,int _data)
{
    if(root==NULL || ( _data == root->data))
    {
        return root;
    }
    if( _data < root->data )
    {
        return find_node(root->lchild,_data);
    }
    if(_data > root->data)
    {
        return find_node(root->rchild,_data);
    }
}
//查找最小关键字,空树时返回NULL  
Node* search_min(Node* root)
{
    if(root==NULL)
    {
        return NULL;
    }
    if(root->lchild==NULL)
    {
        return root;
    }
    search_min(root->lchild);
}
//查找最大关键字
Node* search_max(Node* root)
{
    if(root==NULL)
    {
        return NULL;
    }
    if(root->rchild==NULL)
    {
        return root;
    }
    search_max(root->rchild);
}
//根据关键字删除某个结点,删除成功返回1,否则返回0  如果把根结点删掉,那么要改变根结点的地址,所以传二级指针
/*思想: 1。若p有左子树,p的左孩子取代它;找到其左子树的最右边的叶子结点r,把p的右子树作为r的右子树。
 2。若p没有左子树,直接用p的右孩子取代它。
*/
void delete_node(Node** root,int _data)
{
    if(root==NULL)
        return ;
    Node* dnode=find_node(*root,_data);
    if(dnode==NULL)
    {
        return ;
    }
    if(dnode->lchild==NULL && dnode->rchild==NULL && dnode!=*root)
    {
        if(dnode->parent->lchild==dnode)
        {
            dnode->parent->lchild=NULL;
        }
        if(dnode->parent->rchild==dnode)
        {
            dnode->parent->rchild=NULL;
        }
        free(dnode);
        dnode=NULL;
        return ;
    }
    //如没有左子树
    if(dnode->lchild==NULL)
    {
        //若这个节点是根节点
        if(dnode==*root)
        {
            *root=(*root)->rchild;
            (*root)->parent=NULL;
            free(dnode);
            return ;
        }
        //若这个节点是父节点的左孩子
        if(dnode->parent->lchild==dnode)
        {
            dnode->parent->lchild=dnode->rchild;
            dnode->rchild->parent=dnode->parent;
            free(dnode);
            return ;
        }
        //若这个节点是父节点的右孩子
        if(dnode->parent->rchild==dnode)
        {
            dnode->parent->rchild=dnode->rchild;
            dnode->rchild->parent=dnode->parent;
            free(dnode);
            return ;
        }
    }
    if(dnode->lchild!=NULL)
    {
    //找到其左子树的最右边的叶子结点r,把p的右子树作为r的右子树。
        Node* r=dnode->lchild;
        while(r->rchild!=NULL)
        {
            r=r->rchild;
        }
        r->rchild=dnode->rchild;
        dnode->rchild->parent=r->rchild;
        //用dnode的左节点来取代ta
        if(dnode==*root)
        {
            *root=dnode->lchild;
            (*root)->parent=NULL;    
        }
        else
        {
            if(dnode->parent->lchild==dnode)
            {
                dnode->parent->lchild=dnode->lchild;
                dnode->lchild->parent=dnode->parent;
            }
            if(dnode->parent->rchild==dnode)
            {
                dnode->parent->rchild=dnode->lchild;
                dnode->lchild->parent=dnode->parent;
            }
        }
        free(dnode);
        dnode=NULL;
    }
}
int main(int argc, char const *argv[])
{
    Node* root=NULL;
    insert_node(&root,15);
    insert_node(&root,6);
    insert_node(&root,18);
    insert_node(&root,3);
    insert_node(&root,7);
    insert_node(&root,17);
    insert_node(&root,20);
    
    print_tree(root);
    printf("\n");
    Node* f=find_node(root,6);
    if(f!=NULL)
    {
        printf("%d\n",f->parent->data);
    }
    delete_node(&root,3);
    print_tree(root);
    printf("\n");
    return 0;
}
时间: 2024-08-10 17:09:25

二叉查找树的基本操作实现的相关文章

二叉查找树的基本操作例程

对于二叉查找树的最大难处,我觉得是在于删除,当删除一个元素时,简单地说有两种情况,一种是节点,一种是叶子.假设被删除值为D 1.叶子,很简单,找到叶子的父节点,然后将这个父节点指向该叶子的树枝赋为0:有一种特殊情况是就一个根,那么释放根,然后返回0. 2.节点,需要做两步,找到该节点的左子树的最大值或者右子树的最小值,假设为F,用F替代被删除节点的值D,然后再删除F,而F肯定是叶子,采用1中的方法. 这种算法删除时最坏的情况就是删除点是一个节点,首先遍历一遍找到该节点D,然后再遍历该节点的某个子

二叉查找树的基本操作

二叉查找树:对于树中的每个节点X,它的左子树所有关键字小于X的关键字,而右子树的所有关键字大于X的关键字. 二叉查找树的平均深度是O(logN). 二叉查找树的删除操作: 如果节点是一片树叶,可以立即删除. 如果有一个儿子,调节父节点指针绕过该节点后被删除. 如果有两个儿子,用右子树的最小数据代替该节点的数据,并递归地删除那个节点(现在它是空的).因为右子树的最小节点不可能有左儿子,所以第二次删除更容易. 1 #ifndef _Tree_H 2 3 struct TreeNode; 4 type

二叉树学习笔记之二叉查找树(BSTree)

二叉查找树即搜索二叉树,或者二叉排序树(BSTree),学习回顾一下有关的知识. >>关于二叉查找树 二叉查找树(Binary Search Tree)是指一棵空树或者具有下列性质的二叉树:1. 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值:2. 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值:3. 任意节点的左.右子树也分别为二叉查找树.4. 没有键值相等的节点,这个特征很重要,可以帮助理解二叉排序树的很多操作.二叉查找树具有很高的灵活性,对其优化可

(3) 二叉查找树(二叉搜索树)

一.什么是二叉查找树? 二叉查找树, 或者是一个空树, 或者是具有如下性质的二叉树: (1).若它的左子树不空,则其左子树上的所有结点的值均小于它根结点的值: (2).若它的右子树不空,则其右子树上的所有结点的值均大于它根结点的值: (3).它的左.右子树也分别为二叉查找树. 下图就是一颗二叉查找树 二叉查找树是具有特殊性质的二叉树, 其节点数据结构定义如下: package searchTree; /** * Created by xinfengyao on 16-12-28. */ publ

数据结构-二叉树和二叉查找树

先按树-二叉树-二叉查找树的顺序解释会比较清楚. 一,树 树(Tree)是n(n≥0)个结点的有限集.在任意一棵非空树中: (1)有且仅有一个特定的被称为根(Root)的结点: (2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1,T2,-,Tm,其中每一个集合本身又是一棵树,并且称为根的子树(SubTree). 结点的度(Degree):结点拥有的子树数称为结点的度(Degree).度为0的结点称为叶子(Leaf)或终端结点.度不为0的结点称为非终端结点或分支结点. 树的度:是

B树(B+树) 学习总结

一,B树的定义及介绍 为什么会有B树? 熟悉的树的结构有二叉树查找树或者平衡二叉树……平衡二叉树保证最坏情况下各个操作的时间复杂度为O(logN),但是为了保持平衡,在插入或删除元素时,需要进行旋转啊...一系列操作,因此实现起来比较复杂.而对于二叉查找树,基本操作在最坏情况下会出现O(N)的时间复杂度.总之,这些树都是针对于内存中的数据操作,它们每个结点最多只有两个孩子,当数据量大时(结点数目很多),就会导致树很高.但由于基本操作(查找元素.插入元素)都是在内存中实现,因此,树高点也就没有太大

算法导论-二叉查找数

目录 引言 二叉查找树 节点定义 查找操作 插入操作 删除操作 二叉查找树存在问题 完整源码 讨论区 参考资料 内容                             1.引言                                   前面的文章介绍过二分查找.散列表查找:二分查找效率为Θ(lgn).二分查找要求数组是静态的,即元素不能动态的插入和删除,否则会耗费较多的时间:散列表查找效率可以到达Θ(1),但是一般用于“等于性查找“,不能进行“范围查找”;本文介绍的二叉查找树,(

算法导论 第13章 红黑树

二叉查找树的基本操作包括搜索.插入.删除.取最大和最小值等都能够在O(h)时间复杂度内实现,因此能在期望时间O(lgn)下实现,但是二叉查找树的平衡性在这些操作中并没有得到维护,因此其高度可能会变得很高,当其高度较高时,而二叉查找树的性能就未必比链表好了,所以二叉查找树的集合操作是期望时间O(lgn),最坏情况下为O(n). 红黑树也是一种二叉查找树,它拥有二叉查找树的性质,同时红黑树还有其它一些特殊性质,这使得红黑树的动态集合基本操作在最坏情况下也为O(lgn),红黑树通过给节点增加颜色和其它

C++二叉树的实现

C++实现二叉查找树 啥是二叉查找树 在数据结构中,有一个奇葩的东西,说它奇葩,那是因为它重要,这就是树.而在树中,二叉树又是当中的贵族.二叉树的一个重要应用是它们在查找中的应用,于是就有了二叉查找树. 使二叉树成为一颗二叉查找树,需要满足以下两点: 对于树中的每个节点X,它的左子树中所有项的值都要小于X中的项: 对于树中的每个节点Y,它的右子树中所有项的值都要大于Y中的项. 二叉查找树的基本操作 以下是对于二叉查找树的基本操作定义类,然后慢慢分析是如何实现它们的. template<class