第六章 树和二叉树

文章目录

    • 写在前面
    • 定义和术语
    • 性质
    • 遍历(递归)
    • 遍历(非递归)
    • 练习题
    • 完全二叉树的顺序存储
    • 线索二叉树
    • 森林与二叉树的转换
    • 赫夫曼树
    • 二叉查找树(二叉搜索树)
    • 二叉平衡树
    • 并查集

写在前面

终于写到树了。。。。我实在是太懒了T_T!
到树和图可能写的不是很全面,一些比较基础的东西我就不赘述了,毕竟这是复习不是预习
这篇关于树的博客,内容涉及到了一些可能我们课上老师没讲的内容,比如堆、二叉查找树、二叉平衡树、并查集。
因为我是结合了浙江大学陈越与何钦铭教授的慕课《数据结构》的课程内容来做的总结,所以不懂的部分,可以参考慕课。
后边还有一部分没写完,我有空了就补,我实在是太懒了。。。。

定义和术语

  1. 节点的度:一个节点含有的子树的个数称为该节点的度。
  2. 二叉树:是每个结点至多有两棵子树的树,且子树有左右之分,次序不可颠倒。
  3. 节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推。
  4. 树的深度:树中结点的最大层次称为树的深度。
  5. 满二叉树:一棵深度为k,且有2^k-1 (2的k次方减一)个节点的二叉树称之为满二叉树。
  6. 完全二叉树:深度为k,有n个结点的二叉树,且其中每一个结点都与深度为k的满二叉树中编号从1至n的结点一一对应。

性质

  1. 性质一:在非空二叉树中,第i层的结点总数不超过2^(i-1),i>=1。
  2. 性质二:深度为k的二叉树最多有2^k-1个结点(k>=1),最少有k个结点。
  3. 性质三:对于任意一棵二叉树T,如果其叶结点数为N0,而度数为2的结点总数为N2,则N0=N2+1.
  4. 性质四:具有n个结点的完全二叉树的深度为K =⌊log2n⌋+1(取下整数) 。
  5. 性质五:完全二叉树,如果2i<=N,则其左儿子的编号为2i;若2i>N,则无左儿子。如果2i+1<=N,则其右儿子的结点编号为2i+1;若2i+1>N,则无右儿子。
  6. 扩展:给定N个节点,能构成h(N)种不同的二叉树。h(N)为卡特兰数的第N项。h(n)=C(2*n,n)/(n+1)。

遍历(递归)

用下面这个例子来实现以下遍历算法。
第六章 树和二叉树_第1张图片
这里先给出三种遍历方法的递归写法
比较简单 递归的程序最好写 但是要知道 所有的递归程序都可以转成非递归实现
毕竟 递归的本质就是压栈与弹栈操作

//输入ABD^^E^^C^^
//输出:
//ABDEC(先序结果
//DBEAC(中序结果
//DEBCA(后序结果

#include
#include
typedef struct BiTNode{
    char ch;
    struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
int CreateBiTree(BiTree *T){//按照先序创建二叉树
    char str;
    str=getchar();
    if(str=='^') *T=NULL;
    else{
        *T=(BiTree)malloc(sizeof(BiTNode));
        (*T)->ch=str;
        CreateBiTree( &( (*T)->lchild ) );
        CreateBiTree( &( (*T)->rchild ) );
    }
}
int PreOrderTraverse(BiTree T){//先序遍历
    if(T!=NULL){
        printf("%c",T->ch);
        PreOrderTraverse(T->lchild);
        PreOrderTraverse(T->rchild);
    }
}
int InOrderTraverse(BiTree T){//中序遍历
    if(T!=NULL){
        InOrderTraverse(T->lchild);
        printf("%c",T->ch);
        InOrderTraverse(T->rchild);
    }
}
int PostOrderTraverse(BiTree T){//后序遍历
    if(T!=NULL){
        PostOrderTraverse(T->lchild);
        PostOrderTraverse(T->rchild);
        printf("%c",T->ch);
    }
}
int main(){
    BiTree T;
    CreateBiTree(&T);
    PreOrderTraverse(T);printf("\n");
    InOrderTraverse(T);printf("\n");
    PostOrderTraverse(T);printf("\n");
}

遍历(非递归)

遍历的递归写法比较简单,所以多注意一下非递归写法
尤其是后序遍历(非递归),还是比较麻烦的

//输入ABD^^E^^C^^
//输出:
//ABDEC(先序结果
//DBEAC(中序结果
//DEBCA(后序结果
#include
#include
#define maxn 100
typedef struct BiTNode{
    char ch;
    struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
int CreateBiTree(BiTree *T){//按照先序创建二叉树
    char str;
    str=getchar();
    if(str=='^') *T=NULL;
    else{
        *T=(BiTree)malloc(sizeof(BiTNode));
        (*T)->ch=str;
        CreateBiTree( &( (*T)->lchild ) );
        CreateBiTree( &( (*T)->rchild ) );
    }
}
int PreOrderTraverse(BiTree T){//先序遍历
    BiTree stack[maxn];
    int i=0;
    stack[0]=NULL;
    while(T!=NULL||i>0){
        if(T!=NULL){
            printf("%c",T->ch);
            stack[++i]=T;//压栈
            T=T->lchild;
        }
        else{
            T=stack[i--];//弹栈
            T=T->rchild;
        }
    }
}
int InOrderTraverse(BiTree T){//中序遍历
    BiTree stack[maxn];
    int i=0;
    stack[0]=NULL;
    while(i>=0){
        if(T!=NULL){
            stack[++i]=T;//压栈
            T=T->lchild;
        }
        else{
            T=stack[i--];//弹栈
            printf("%c",T->ch);
            T=T->rchild;
        }
        if(T==NULL&&i==0) break;
    }
}
int PostOrderTraverse(BiTree T){//后序遍历
    BiTree stack[maxn];
    int b[maxn];
    int i=0;
    stack[0]=NULL;
    do{
        if(T!=NULL){
            stack[++i]=T;
            b[i]=0;
            T=T->lchild;
        }
        else{
            T=stack[i--];
            if(b[i+1]==0){
                stack[++i]=T;
                b[i]=1;
                T=T->rchild;
            }
            else{
               printf("%c",T->ch);
               T=NULL;
            }
        }
    }while(T!=NULL||i>0);
}
int main(){
    BiTree T;
    CreateBiTree(&T);
    PreOrderTraverse(T);printf("\n");
    InOrderTraverse(T);printf("\n");
    PostOrderTraverse(T);printf("\n");
}

练习题

---->统计二叉树中度为0,1和2的结点个数
---->已知二叉树的后序和中序遍历结果 求前序结果
---->二叉树的高

完全二叉树的顺序存储

由于完全二叉树的性质,所以使得他可以采用顺序存储
借助前面给出的性质五,在顺序存储中我们可以快速的访问到他的左右孩子
这个大多时候时候会考计算题,填空题,所以要熟练他的存储方式,会计算
第六章 树和二叉树_第2张图片
代码实现
---->判断完全二叉树

线索二叉树

这个,当初学习的时候,我写过,但是当时可能写的注释不是很清楚
不过这个不是很难理解,跟着算法走一遍大概就能明白了
我先把链接贴出来,随后如果需要分析的话,我再增加注释。
---->线索二叉树代码及示例

森林与二叉树的转换

(待更新

赫夫曼树

通过构造赫夫曼树,我们可以得到赫夫曼编码
算法代码戳下面的链接
---->赫夫曼编码

(待更新

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

---->BST二叉搜索树(查找树)实现 代码+详解(C/C++)
练习题:
---->进击的二叉查找树

二叉平衡树

(待更新

并查集

---->并查集详解

并查集模板

//total数组用来计数
//Find找根节点
//Merge 合并两个集合
int fa[N],total[N];
void init(int n){for(int i=0;i<=n;i++)fa[i]=i,total[i]=1;} 
int Find(int x){return fa[x]==x?x:fa[x]=Find(fa[x]);}
void Merge(int a,int b){
    int p1=Find(a),p2=Find(b);
    if(p1!=p2)total[p1]+=total[p2],fa[p2]=p1;
}

你可能感兴趣的:(数据结构(严蔚敏版))