2. 二叉树 BinTree

二叉树的实现

BinNode : 二叉树结点

BinNode

二叉树结点结构代码 :

#define BinNodePosi BinNode *

struct BinNode
{
    BinNodePosi parent, lchild, rchild;
    T Data;                                      //数据项,数据类型为T
    int height;                                  //该结点的高
    int size();                                  //子树的规模,包括该节点
    int color;                                  // 节点的颜色,RB-Tree使用
    BinNodePosi insertAsLC(T const &);           //作为左孩子插入新结点
    BinNodePosi insertAsRC(T const &);          //作为右孩子插入新结点
    BinNodePosi succ();                         //中序遍历下,当前结点的直接后继
    void travLevel();    //该结点(包括该结点)所在的子树层次遍历
    void travPre();      //该结点(包括该结点)所在的子树先序遍历
    void travIn();       //该结点(包括该结点)所在的子树中序遍历
    void travPost();     //该结点(包括该结点)所在的子树后续遍历
};


二叉树常用接口实现

  1. 将新结点作为左/右孩子插入
    • BinNodePosi insertAsLC(T const &); //作为左孩子插入新结点
    • BinNodePosi insertAsRC(T const &); //作为右孩子插入新结点
/* 创建一个新结点,该结点之后作为左孩子结点 */
BinNodePosi insertAsLC(T const &e)
{
    BinNodePosi lChild = new BinNode(e, this);  //this指针:父结点为当前结点;条件 : this.LC == NULL
    
    return lChild;
}

/* 创建一个新结点,该结点之后作为右孩子结点 */
BinNodePosi insertAsRC(T const &e)
{
    BinNodePosi rChild = new BinNode(e, this);  //this指针:父结点为当前结点;条件 : this.RC == NULL
    
    return rChild;
}
  1. 规模 size : 返回包括当前结点在内的所有后代的总数
int size()
{
    int s = 1;                               //计入自身
    if (lchild)
    {
        s + = lchild->size();               //递归计入左子树的规模
    }
    if (rchild)
    {
        s + = rchild->size();               //递归计入右子树的规模
    }

    return s;
}
  1. 高度更新
    某结点插入或删除后代结点,可能其高度以及其祖先结点的高度都会更新;(从插入或删除的结点的父结点[第一个高度可能更新的结点]开始更新)

[注] 结点高度 : 约定空(子)树高度为 0;单结点(子)树高度为 0

#define NodeHeight(p) ((p) ? p->height : 0)       //节点高度,约定空树的节点高度为 0

/* 更新当前结点 x 的高度 */
int updateHeight(BinNodePosi x)
{
    return x->height = 1 + max(NodeHeight(x->lchild), NodeHeight(x->rchild));
}

/* 更新 x 的高度及其历代祖先的高度 */
void updateHeightAbove(PinNodePosi x)
{
    while (x)
    {
        updateHeight(x);
        x = x->parent;
    }
    
    return;
}
  1. 结点插入
/* 新节点作为 x 节点的左孩子插入 */
BinNodePosi insertAsLC(BinNodePosi x, T const &e)
{
    _size ++;  //整体规模 +1
    x->insertAsLC(e);    // BinNode 结构体中的接口
    updateHeightAbove(x);    // x的历代祖先(包括x)的高度 *可能*增加,其余节点*必然不变*
  
    return  x->lchild;
}

/* 新节点作为 x 节点的右孩子插入 */
BinNodePosi insertAsRC(BinNodePosi x, T const &e)
{
    _size ++;  //整体规模 +1
    x->insertAsRC(e);    // BinNode 结构体中的接口
    updateHeightAbove(x);    // x的历代祖先(包括x)的高度 *可能*增加,其余节点*必然不变*
  
    return  x->rchild;
}


二叉树遍历算法实现

1. 先序遍历(Pre_order)
二叉树先序 :
  • 先根节点
  • 先序遍历根节点的左子树
  • 先序遍历根节点的右子树

遍历顺序 : 节点 --- 左孩子 --- 右孩子

  • 1.1 递归实现二叉树先序遍历算法

补上递归实现的图解

/* 递归实现*/
void traversePre(BinNodePosi x)
{
    if (NULL == x)       //递归出口
    {
        return;
    }

    Visit(x);                    // Visit()为访问节点数据函数
    traversePre(x->lchild);      //先序遍历左子树
    traversePre(x->rchild);      //先序遍历右子树

}
  • 1.2 非递归实现二叉树先序遍历算法 --- "实现1"

补上非递归实现方式1的图解

/* 非递归实现 code 1 */

  • 1.3 非递归实现二叉树先序遍历算法 --- "实现2"

补上非递归实现方式2的图解

/* 非递归实现 code 2 */


2. 中序遍历(In_order)
二叉树中序 :
  • 中序遍历根节点的左子树
  • 访问根节点
  • 中序遍历根节点的右子树

遍历顺序 : 左孩子 --- 节点 --- 右孩子

  • 2.1 递归实现二叉树中序遍历算法

补上递归实现方式的图解

/* 递归实现 code */

  • 2.2 非递归实现二叉树中序遍历算法

补上非递归实现方式的图解

/* 非递归实现 code 1 */


3. 后序遍历(Post_order)
二叉树后序 :
  • 后序遍历根节点的左子树
  • 后序遍历根节点的右子树
  • 访问根节点

遍历顺序 : 左孩子 --- 右孩子 --- 节点

  • 3.1 递归实现二叉树后序遍历算法

补上递归实现方式的图解

/* 递归实现 code */

  • 3.2 非递归实现二叉树后序遍历算法

补上非递归实现方式的图解

/* 非递归实现 code */


4. 层次遍历 (广度遍历)


5. 补充

对于二叉树,树的遍历通常就以上四种:先序遍历、中序遍历、后序遍历、广度优先遍历。(前三种亦统称深度优先遍历)
对于多叉树,树的遍历通常有两种:深度优先遍历、广度优先遍历。
这里补上之后整理的多叉树的深度和广度遍历链接



二叉树的重构

已知某二叉树的遍历序列,如何重构?条件是什么?

  • 任一二叉树 : 三种遍历序列(Pre, In, Post)
  • 已知 [ 先序 / 后序 ] + 中序,即可重构一棵二叉树

[分析]
只靠 先序 + 后序,当出现子树为空的情况,无法判断子树是 L or R,造成分歧。

但是在一种情况下, 先序 + 后序 可构造出唯一对应的二叉树。

  • [ 先序 + 后序 + 真二叉树 ]

真二叉树 : 分叉数为偶数个(0,2)



补充:二叉树的几种分类
  1. 真二叉树:所有节点的度不为1,即叶子节点的度为0,其他节点的度为2

  2. 完全二叉树:若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树

  3. 满二叉树:完全二叉树的一种特殊情况,所有叶节点同处于最底层,每一层的节点数都达到饱和,称为满二叉树



二叉树的应用

1. 二叉树的深度 : "输入根节点,求该树的深度"
2. 输入二叉树的根节点,判断其是否是平衡二叉树

判断某一节点是否平衡的标准 : 其左右子树的深度之差的绝对值是否不大于 1
判断一棵二叉树是否平衡 : 其所有节点是否平衡

3. BST面试题1(from 《剑指offer》27):二叉搜索树和双向链表
4. BST面试题2(from 《剑指offer》50):树中两个节点的最低公共祖先

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

推荐阅读更多精彩内容

  • 四、树与二叉树 1. 二叉树的顺序存储结构 二叉树的顺序存储就是用数组存储二叉树。二叉树的每个结点在顺序存储中都有...
    MinoyJet阅读 1,529评论 0 7
  • 数据结构和算法--二叉树的实现 几种二叉树 1、二叉树 和普通的树相比,二叉树有如下特点: 每个结点最多只有两棵子...
    sunhaiyu阅读 6,462评论 0 14
  • B树的定义 一棵m阶的B树满足下列条件: 树中每个结点至多有m个孩子。 除根结点和叶子结点外,其它每个结点至少有m...
    文档随手记阅读 13,221评论 0 25
  • 二叉树 二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(...
    n油炸小朋友阅读 779评论 0 1
  • 为人处世大全 为人处世,是一辈子的学问。 1、为人 气不和时少说话,有言必失;心不顺时莫做事,做事必败。 事莫虚应...
    闻方培训师阅读 800评论 0 6