No39. 二叉树总结

文章目录

\color{orange}{1.定义}
\color{red}{2.名词区分}
\color{green}{3.一些定理和结论}
\color{pink}{4.遍历}
\color{purple}{5.二叉树的应用}
\color{blue}{6.Reference}

1.定义

1.二叉树:一颗二叉树由结点的有限集合组成,这个集合或者为空,或者由一个根结点及两颗不相交的二叉树组成。
<font color="#ff0000">注意</font>:左右子树不相交,说明它们没有公共的节点,公共的节点意思是数值相同,指针域也相同。

2.满二叉树:满二叉树的每一个结点或者是一个分支结点(非叶结点),并恰好有两个非空子结点。或者是叶结点。


1

3.完全二叉树:从根结点起每一层从左至右填充,一颗高度为d的完全二叉树除了底层(最后一层,即d-1层)以外,每一层都是满的。底层的叶子结点集中在左边的若干位置上。

2

2.名词区分

<font color="#ff0a0a0">高度,深度,层数</font>:
结点M的深度(depth)就是从根结点到M的路径长度。数的高度(height)等于最深结点的深度加1,任何深度为d的结点的层数也是d,根结点的层数和深度都是0

3.一些定理和结论

  • 一棵有n个结点的二叉树的形态总共有{{C^n_{2n}}\over {n+1}}种

    4

    (详细介绍:卡特兰数及其应用

  • 满二叉树定理:非空满二叉树的叶结点数等于其分支结点数加1
    (简单理解:假设一棵有n-1个分支结点的二叉树满足上面的结论,当某棵二叉树有n个分支结点时,选中一个分支结点,这个分支结点的左右子结点都是叶子结点,然后把这2个叶子结点都删掉(后果是删了一个分支结点,删了一个叶子结点),形成的新的二叉树满足之前的归纳假设,所以原二叉树也满足结论。)

    推论:一颗非空二叉树空子树的数目等于 其结点数目加1

4.遍历

先根遍历

2

(图片来源:https://images.app.goo.gl/fdMEerRMHvwLd46Z7)

后根遍历和中根遍历也是顾"名"思"义"的。

(1)由中根遍历和先根遍历确定树的唯一形态

简要思路(证明)

\begin{aligned} &设中根遍历的结果是:A_1,A_2,A_3,...,A_k\\ &设先根遍历的结果是:B_1,B_2,B_3,...,B_k\\ &归纳假设1,2,3,...,k-1个节点可以的先根和中根可以构成一棵唯一树(k\geq2)\\ &则B_1必然的根结点,设B_1节点对应于中根遍历的A_m(1\leq m\leq k)\\ &进一步得:\\ &A_1,A_2,...,A_{m-1}为根结点的左子树\\ &A_{m+1},A_{m+2},...,A_k为根结点的右子树\\ &B_2,B_3,...,B_m为根结点的左子树\\ &B_{m+1},B_{m+2},...,B_k为根结点的右子树\\ &根据归纳假设,上面的左子树和右子树都可以唯一确定,\\ &因此整棵树(有k个结点)可以唯一确定\\ \end{aligned}

代码:

下面代码中用哈希表查找上面证明中m的值,查找的时间复杂度是O(1),否则顺序查找会要O(n)的时间,n为结点个数。
算法(构造唯一树)的整体时间复杂度是O(n)

#include <stdio.h>
#include <stdlib.h>
#define LEN sizeof(Tree)
#define NULLKEY -32768 
typedef struct Tree {
    char element;
    Tree* left;
    Tree* right;
};
void preOrder(Tree* root) {
    if (root == NULL)return;

    printf("%c ", root->element);
    preOrder(root->left);
    preOrder(root->right);
}
void inOrder(Tree* root) {
    if (root == NULL)return;

    inOrder(root->left);
    printf("%c ", root->element);
    inOrder(root->right);
}
void postOrder(Tree* root) {
    if (root == NULL)return;

    postOrder(root->left);
    postOrder(root->right);
    printf("%c ", root->element);
}
void freeAll(Tree* root) {
    if (root == NULL)return;

    freeAll(root->left);
    freeAll(root->right);
    free(root);
}
typedef struct
{
    int* elem;                      //基址
    int count;                      //当前数据元素个数 
}HashTable;

int Search(char* Array, HashTable* hashTable, int data);

//核心函数
Tree* strucrTree(char* pre, char* in, int start,int end,HashTable& ht) {
    //index记录先根遍历的父节点位置,最开始是根结点
    static int index = 0;
    if (start > end)
        return NULL;
    Tree* root = (Tree*)malloc(sizeof(Tree));
    root->element = pre[index++];
    root->left = NULL;
    root->right = NULL;
    if (start == end)
        return root;
    //in_index记录index对应节点在中根遍历中的位置
    int in_index = Search(in,&ht, pre[index]);
    root->left = strucrTree(pre, in, start, in_index - 1, ht);
    root->right = strucrTree(pre, in, in_index+1, end , ht);
    return root;
}

int m = 0; // 哈希表长度

/*初始化*/
int Init(HashTable* hashTable,int size)
{
    int i;
    m = 2*size;
    hashTable->elem = (int*)malloc(m * sizeof(int)); //申请内存
    hashTable->count = m;
    for (i = 0; i < m; i++)
    {
        hashTable->elem[i] = NULLKEY;
    }
    return 1;
}

/*哈希函数*/
int Hash(int data)
{
    return data % m;
}

/*插入*/
void Insert(HashTable* hashTable, int key,int value)
{
    int hashAddress = Hash(key); //求哈希地址

    //发生冲突
    while (hashTable->elem[hashAddress] != NULLKEY)
    {
        //利用开放定址的线性探测法解决冲突
        hashAddress = (++hashAddress) % m;
    }

    //插入值
    hashTable->elem[hashAddress] = value;
}

/*查找*/
int Search(char* Array,HashTable* hashTable, int data)
{
    int hashAddress = Hash(data); //求哈希地址

    //发生冲突
    while (Array[hashTable->elem[hashAddress]] != data)
    {
        //利用开放定址的线性探测法解决冲突
        hashAddress = (++hashAddress) % m;

        if (hashTable->elem[hashAddress] == NULLKEY || hashAddress == Hash(data)) return -1;
    }

    //查找成功
    return hashTable->elem[hashAddress];
}
int main() {
    char preorder[8] = { '1','2','4','6','5','7','3','8' };
    char inorder[8] = { '6','4','2','5','7','1','3','8' };
    int length = sizeof(inorder);
    Tree* root = (Tree*)malloc(LEN);
    HashTable hashtable;
    Init(&hashtable, length);
    for (int i = 0; i < length; ++i) {
        Insert(&hashtable, inorder[i],i);
    }
    root = strucrTree(preorder, inorder, 0,length-1, hashtable);
    preOrder(root);
    freeAll(root);
}

5.二叉树的应用

1.二叉检索树
2.表达式树
3.利用最大堆实现优先队列
4.最小堆和哈夫曼编码

6.Reference

1.《数据结构与算法分析(C++版)(第三版)》第5章 二叉树
2.https://images.app.goo.gl/fdMEerRMHvwLd46Z7

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

推荐阅读更多精彩内容

  • 树形结构是一种十分重要的数据结构。二叉树、树与树林都属于树形结构。 树形结构每个结点最多只有一个前驱结点,但可以有...
    cain_huang阅读 1,889评论 0 11
  • 1.树和二叉树的定义 (1) 树的定义 树是n (n≥0) 个结点的有限集。 n=0 时称为空树。在任意一棵非空树...
    yinxmm阅读 2,359评论 0 3
  • 树和二叉树 1、树的定义 树(Tree)是由一个 或 多个结点 组成的有限集合T,且满足: ①有且仅有一个称为根的...
    利伊奥克儿阅读 1,269评论 0 1
  • 二叉树 二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(...
    n油炸小朋友阅读 731评论 0 1
  • 一、树的基本概念 1.1树的定义 树是 N(N>=0) 个结点的有限集合,N = 0 时,称为空树,这是一种特殊的...
    末雨潮声阅读 669评论 0 0