二叉树的基本操作(FID)

二叉搜索树

首先回顾一下:
查找问题:

  1. 静态查找与动态查找;
  2. 针对动态查找,数据如何组织;
  • 静态查找:要查找的元素是不动的,就是在一个集合中,主要做的是find操作,没有delete 和 insert 操作的发生;
  • 动态查找:集合中,除了有find操作,还经常伴随着delete 和 insert 操作。

对于静态查找,我们会经常使用一个非常高效的查找算法----二分查找。它将查找的时间复杂度从 O(n) 直接降为 O(log n)。

二分查找要求集合要有序

为什么二分查找的效率这么好?

因为二分查找事先将要查找的数据进行了有序化操作。这样就把一个线性操作转化为一个类似于树的操作,查找的效率就是树的高度。从这里我们可以得到启发,能不能将数据直接存到树上,而不是将数据存入数组中,然后再采用类似于树的操作,即:减少了中间过程。PS: 树的动态性好,方便进行insert 和 delete 。

将数据直接放在树上面肯定是可行的,但是我们应该如何组织这棵树呢?我们可以尝试,让一个结点满足下列要求:

  1. 所有的左子树都小于该结点;
  2. 所有的右子树都大于该节点;

这样我们的查找过程就变成了一个对当前结点的一个判断。这样就大大缩小我们的查找范围。

我们上面期望的那种树在数据结构中早有定论:二叉搜索树

二叉搜索树的概念

二叉搜索树(BST,Binary Search Tree),亦称为:二叉排序树 or 二叉查找树。

二叉搜索树可以为空。如果不为空,则应满足:

  1. 非空左子树的所有键值 小于 其根节点的键值;
  2. 非空右子树的所有键值 大于 其根节点的键值;
  3. 左、右子树都是二叉搜索树;

二叉搜索树的常用操作:

  1. 查找操作:
  • position Find(ElementType X, BinTree BST):从二叉搜索树BST中查找元素X,返回其所在结点的地址;

查找原理:查找从根节点开始,如果树为空,返回NULL; 若搜索树非空,则根节点和X进行比较,并进行不同的处理:1.若X < 根节点键值,只需左子树中继续搜索;2.如果X大于根节点的键值,在右子树中进行继续搜索;3.若两者比较结果是相等,搜索完成,返回指向此节点的指针。代码如下:

BinTree Find(ElementType X,BinTree BST){
    if(!BST) return NULL ;
    if(X > BST ->Data){
        // 继续查找右子树
        return Find(X,BST->Right);
    }else(X < BST -> Left){
        // 继续查找左子树
        return Find(X,BST-Left);
    }else{
        // 查找成功
        return BST;
    }
}

我们可以发现上面的代码实现方式是递归实现,且都是尾递归实现

尾递归:在程序即将返回的时候才进行递归;且尾递归都可以采用循环来实现

由于非递归函数的执行效率高,可将"尾递归"改为"迭代"函数

BinTree iterFind(ElementType X ,BinTree BST){
    while(BST){
        if(X > BST ->Data){
            BST = BST -> Right; 
        }else if(X <  BST -> Data){
            BST = BST -> Left;
        }else{
            return BST;
        }
    }
    return NULL ;
}

查找的效率决定于树的高度,如果都在左边 or 都在右边形成一条链,那么查找的效率就是O(n-1),我们的目标是O(log n),这就需要树的结构尽量左右对称,也就是以后要谈的平衡二叉树

  • position FindMin(BinTree BST): 从二叉搜索树BST中查找并返回最小元素所在结点的地址;

最小元素一定是在树的最左分支的端节点上;(min 即最左叶子结点)

/*尾递归 查找最小元素*/
BinTree FindMin(BinTree BST){
    if(BST == NULL)  return  NULL;

    if(BST->Left  != NULL){
        return FindMin(BST -> Left);
    } else{
        return BST;
    }
}

改为:迭代函数

BinTree FindMin(BinTree BST){
    if(BST != NULL){
        while(BST -> Left != NULL){
            BST = BST -> Left;
        }
    return BST;
    }
}
  • position FindMax(BinTree BST): 从二叉搜索树BST中查找并返回最大元素所在结点的地址;

最大元素一定是在树的最右分支的端结点上;(max 即最右叶子结点)

/*尾递归 查找最大元素*/
BinTree FindMax(BinTree BST){
    if(BST == NULL)  return  NULL;

    if(BST->Right  != NULL){
        return FindMax(BST -> Right);
    } else{
        return BST;
    }
}

改为:迭代函数

BinTree FindMax(BinTree BST){
    if(BST != NULL){
        while(BST -> Right != NULL){
            BST = BST -> Right;
        }
    return BST;
    }
}
  1. 插入操作:
  • BinTree Insert(ElementType X,BinTree BST):

二叉搜索树的插入:关键是要找到元素应该插入的位置,可以采用与Find类似的方法

/*二叉搜索树的插入算法*/
BinTree Insert(ElementType X,BinTree BST){
    if(BST == NULL){
        /*若原树为空,生成并返回一个结点的二叉搜索树*/
        BST = malloc(sizeof(struct TreeNode));
        BST -> Data = X ;
        BStT -> Left  = BST -> Right = NULL;
    }else{
        if(X < BST -> Data){
            // 递归 插入左子树
            BST -> Left = Insert(X,BST -> Left);
        }else if(X > BST -> Data){
            // 递归 插入右子树
            BST -> Right = Insert(X,BST -> Right);
        }
    }
    return BST;
}
  1. 删除操作:
  • BinTree Delete(ElementType X,BinTree BST):

二叉树的删除分为多种情况:

  1. 要删除的是叶子结点

直接删除,并再修改其父结点指针---置为NULL


要删除的是叶子结点
  1. 要删除的结点只有一个孩子结点:

将其父结点的指针指向要删除结点的孩子结点

要删除的结点只有一个孩子结点

del31.png
  1. 要删除的结点有左右两颗子树:

用另一结点替代被删除结点:右子树的最小元素 or 左子树的最大元素

复杂的问题简单化,将此种情况转化为上述两种情况之一

取右子树中的最小元素替代del31.png

取左子树中的最大元素替代
BinTree Delete(ElementType X,BinTree BST){
    Position Tmp;
    if(BST == NULL) printf("要删除的元素未找到");

  if(X < BST -> Data){
      // 左子树递归删除
      BST -> Left = Delete(X, BST -> Left);
  }else if(X > BST -> Data){
      // 右子树递归删除
      BST -> Right = Delete(X,BST -> Right);
  }else{
      // 找到要删除的结点
      if(BST -> Left != NULL && BST -> Right != NULL){
          //被删除结点有左右两个子结点
          Tmp = FindMin(BST -> Right);
          // 策略1:在右子树中找最小的元素替代被删除结点
          BST -> Data = Tmp -> Data;
          // 在删除结点的右子树中删除最小元素  
          BST -> Right = Delete(BST -> Data,BST -> Right);
      }else{
          // 被删除结点有一个or无子结点
          Tmp = BST;
          if(BST -> Left == NULL){
              // 有右孩子or 无子结点
              BST = BST -> Right;
          }else if(BST -> Right == Right){
              // 有左孩子or 无子结点
              BST = BST -> Left;
          }
          free(Tmp);
      }
  }
  return BST;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • B树的定义 一棵m阶的B树满足下列条件: 树中每个结点至多有m个孩子。 除根结点和叶子结点外,其它每个结点至少有m...
    文档随手记阅读 13,153评论 0 25
  • -二叉搜索树 查找问题:静态查找和动态查找,静态查找可以用二分查找-判定树,那么针对动态查找数据如何组织?(树的动...
    Spicy_Crayfish阅读 1,341评论 0 2
  • 二叉搜索树,平衡树,B,b-,b+,b*,红黑树 二叉搜索树 ​ 1.所有非叶子结点至多拥有两个儿子(Le...
    raincoffee阅读 3,852评论 3 18
  • 一. 算法之变,结构为宗 计算机在很多情况下被应用于检索数据,比如航空和铁路运输业的航班信息和列车时刻表的查询,都...
    Leesper阅读 6,826评论 13 42
  • 0. 什么是树 数据的基本单位是数据元素,在涉及到数据处理时数据元素之间的关系称之为结构,我们依据数据元素之间关系...
    安安zoe阅读 481评论 0 0