数据结构学习-第二次总结

互评作业2-树,二叉树的总结

1-思维导图

2-要点总结

1.树的性质

对于度为k的树:

1、节点数=度数+1

2、第i层最多节点数:k(i-1),i≥1

3、高为i的k叉树节点数最多:(ki-1)/(k-1),i≥1

4、n个节点的k叉树深度最小为:ceil( logk( n(k-1)+1 ) )

2.树的储存结构

多重链表:定长链节点个数(二叉树等)、不定长链节点个数

三重链表:每个节点三个指针域(第一个孩子节点、双亲节点、第一个兄弟节点)

3.二叉树的性质

1、节点数=度数+1

2、第i层节点数:2(i-1),i≥1

3、高为i的二叉树节点数最多:2i-1,i≥1

4、n个节点的二叉树深度最小为:ceil( log2(n+1) ),为理想平衡二叉树时取最小值

5、度为0的节点数=度为2的节点数+1。(因为 节点数n=n0+n1+n2 且 分支数 n-1=n1+2n2,联立可得之)

6、n个节点的完全二叉树从1起对节点从上到下从左到右的编号,编号为i的节点:父节点编号为 floor(i/2),除非该节点已为父节点;左孩子节点编号为2i,除非2i>n即该节点已为叶子节点;右孩子编号为2i+1,除非2i+1>n即右孩子不存在。

推而广之,对于完全m叉树编号为i的节点,其父节点编号为 **floor((i+m-2)/m ) **,第j个孩子编号为 mi+j-m+1

4.二叉树的储存

1、顺序存储:数组。(适用于完全二叉树的存储,一般二叉树可以通过填充虚拟节点当成完全二叉树来存储。缺点是浪费空间)

2、链式存储

二叉链表(左孩子、右孩子):n个节点的二叉树有n+1个空指针域(空指针域即2n0+n1=n2+1+n0+n1=n+1)。线索二叉树通过利用空指针域指向直接前驱、后继节点来避免遍历时使用堆栈,如中序线索二叉树。

三叉链表(父节点、左孩子、右孩子)

5.二叉树的建立与遍历

建立:根据输入的序列构建用二叉链表存储的二叉树。这里假定序列为字符串,每个字符对应树中一个节点。

遍历:根据输入序列构建二叉树时需要遍历输入序列,遍历方式有:前序遍历、中序遍历、后序遍历、层次遍历

6.特殊二叉树

1、理想平衡二叉树(只有最后一层可能不满)

满二叉树(是理想平衡二叉树,且各层都满)

完全二叉树(是理想平衡二叉树,且最后一层节点依次从左填到右)

2、正则(正规)二叉树:只有度为0或2的节点的二叉树

3、线索二叉树:将二叉树的空指针域用来存储直接前驱、直接后继节点(称为线索)的二叉树,这样遍历就不需要用栈了。

通过遍历二叉树进行二叉树的线索化,根据遍历方法的不同分为前序线索二叉树中序线索二叉树后序线索二叉树

前序线索二叉树中不能找到某些节点的直接前驱节点、后序线索二叉树不能找到某些节点的直接后继节点,因此通常用中序线索二叉树。

4、哈夫曼树(最优二叉树):带权路径长度WPL最小的二叉树。

WPL=Σ(叶节点权值×路径长度)= 非根节点的权值和 = 非叶节点的权值和

根节点权值叶节点权值和 相等

没有度为1的节点(即哈夫曼树是正则二叉树)、给定权值序列构造的哈夫曼树不唯一但WPL相同。

5、二叉查找树(亦称二叉排序树、二叉搜索树)BST:每个节点的左子树的所有节点的值小于该节点值,右子树的所有节点值小于该节点值的二叉树。
6,平衡二叉树(亦称平衡二叉查找树、AVL树):每个节点的左右子树深度最多差1的二叉查找树。

7.树与森林的转换

树、森林的遍历:

a、二叉树:前序、中序、后序、层次

b、:前序、后序

c、森林:前序(即按树的前序遍历依次遍历每棵树)、中序(即按树的后序遍历方式依次遍历每棵树)

将树或森林转为二叉树或反向转换后:

二叉树的前序、树的前序、森林的前序遍历序列一样

3-疑难问题及解决方案

疑难问题:

二叉树删除结点函数,如何在删除结点后维持二叉树的性质和形状。

解决方案:构造两个函数,一个负责查找删除,一个负责维持二叉树的性质和形状。

代码展示:


int Delete(BiTree *p){
    
    BiTree q, s;
    
    if ((*p)->rchild == NULL) {  // 右子树空 则只需要重接它的左子树
        
        q = *p;
        *p = (*p)->lchild;
        free(q);
        
    }else if ((*p)->lchild == NULL){  // 左子树空 则只需要重接它的右子树
        
        q = *p;
        *p = (*p)->rchild;
        free(q);
        
    }else{  // 左右子树都不空
        
        q = *p;
        s = (*p)->lchild;
        
        while (s->rchild) {  // 向右到尽头,找到待删结点的前驱
            
            q = s;
            s = s->rchild;
        }
        
        (*p)->data = s->data;  // s 指向被删除结点的直接前驱 (将被删结点前驱的值取代被删结点的值)
        
        if (q != *p)
            q->rchild = s->lchild;  // 重接 q 的右子树
        else
            q->lchild = s->lchild;  // 重接 q 的左子树
        
        free(s);
    }
    
    return TRUE;
}


int DeleteBST(BiTree * T, int key){
    
    if (!*T)   // 不存在关键字等于 key 的元素
        return FALSE;
    else{
        
        if (key == (*T)->data)
            return Delete(T);
        else if (key < (*T)->data)
            return DeleteBST(&(*T)->lchild, key);
        else
            return DeleteBST(&(*T)->rchild, key);
    }
}
posted @ 2020-04-26 11:06  MIKELOVE  阅读(258)  评论(0编辑  收藏  举报