5.1.1 二叉搜索树

来源:互联网 发布:上瘾 顾海 知乎 编辑:程序博客网 时间:2024/06/16 16:58

5.1.1 二叉搜索树

二叉树是指任何节点最多只有两个子节点;而二叉搜索树(也称二叉查找树)的规则如下:

  • 对数时间的元素插入和访问(O(h) == O(lgn))
  • 任何节点键值一定大于其左子树中的每一个节点的键值,一定小于其右子树节点的键值。

根据上面的定义,判断下图中的树哪个不是二叉搜索树:

左边的是,右边的不是;因为根节点的键值6小于左子树中其中一个节点的键值7。请记住:从根节点一直往左(右)走,直到无左(右)路可走,即得最小(大)元素。如下图所示:

5.1.2 操作

二叉搜索树的常用操作有:查找最小/大元素,插入及删除元素。下面给出具体的操作步骤。注意:这里以int型数据作为研究对象,当然可以写成模板,这里一切从简,以聚焦于算法的原理。树中存放节点数据的结构体如下:

struct Node{    int key;              // 以int型数据为例    Node *Left, *Right;   // 指向左右子节点的指针};

每个节点的数据结构包含一个int型键值,两个分别指向左、右子节点的节点指针,当不存在左(或右)子节点时,Left(或Right)为NULL。

5.1.2.1 查找最小节点

要在一颗二叉搜索树中查找最大值或最小值,一直往右或往左走即可。这里只给出查找最小节点的程序,查找最大节点类似,下面代码中的Left换成Right即可;注意边界条件的判断也相当重要,尤其在面试时,不可忘记!!!

// 递归实现Node* findMin(Node* T){    // 边界条件判断    if(T == NULL)        return NULL;    else if(T->Left == NULL)        return T;    else        return findMin(T->Left);}// 非递归实现Node* findMin(Node* T){    if(T == NULL)        return NULL;    while(T->Left != NULL)    {        T = T->Left;    }    return T;}

这里找到了最小的节点(Node* node),那么结构体中的数据轻而易得(node->key)!

5.1.2.2 插入

插入新元素到二叉搜索树中的规则很简单:从根节点开始,遇到键值大的(即新元素的值<节点的键值)往左走,遇到键值小的往右走。

// 递归实现Node* insert(Node* T, int x){    if(!T)// T == NULL    {// 空树->构造一个节点        T = malloc(sizeof(Node));        if(T){            T->key = x;            T->Left = NULL;            T->Right = NULL;            return T;        }else{            //FetalError("Out of space!");        }    }    if(x < T->key)      // 向左走        insert(T->Left, x);    else if(x > T->key) // 向右走        insert(T->Right, x);    return T;  }// 非递归实现Node* insert(Node* T, int x){    if(!T)// T == NULL    {// 空树->构造一个节点        T = malloc(sizeof(Node));        if(T){            T->key = x;            T->Left = NULL;            T->Right = NULL;            return T;        }else{            //FetalError("Out of space!");        }    }    while(x != T->key)    {        if(x < T->key)            T = T->Left;        else            T = T->Right;        if(!T){// 判断是否到达尾端            T = malloc(sizeof(Node));            T->key = x;            T->Left = T->Right = NULL;            break;        }    }    return T;}

5.1.2.3 删除

图5-6是二叉搜索树的元素移除操作图解。欲删除旧节点A,有两种情况:

  • 情形1:节点A(当前根节点)只有一个子节点。即要么有左子节点,要么有子节点;那么,仅需把该子节点连至A节点的父节点,而后再删除节点A;
  • 情形2:节点A(当前根节点)有两个子节点。根据二叉搜索树的性质,左子树所有节点的键值 < 根节点的键值 < 右子树所有节点的键值;那么,欲删除旧节点A,需找到右子树中的最小元素节点(使用findMin函数),而后更新旧节点A的键值(不需要更新指向子节点的指针),最后递归调用delete函数删除右子树的最小元素的节点并更新旧节点A的右子树的根节点(A->Right)。

程序如下:

// 《数据结构和算法分析——C语言描述》,该方法永远返回根节点Node* Delete(Node* T, int x){    Node* tmpNode;    // 依然是边界条件判断    if(!T)        return NULL;    else{// 先找到要删除元素的节点        if(x < T->key)            T->Left = delete(T->Left, x);        else if(x > T->key)            T->Right = delete(T->Right, x);        else{// 找到,要删除的节点为T            if(T->Left && T->Right){// 2个孩子                tmpNode = findMin(T->Right);// 复制一份                T->key = tmpNode->key;                T->Right = Delete(T->Right, T->key);            }else{ // 0或1个孩子                tmpNode = T; // 复制一份                if(!T->Left)                    T = T->Right;                else if(!T->Right)                    T = T->Left;                free(tmpNode);            }        }    }    return T;}   
原创粉丝点击