第五章学习小结

博客介绍了二叉排序树、最小堆、哈夫曼树等特殊树结构的特点。还分享实践课难题讲解心得,提到树的逻辑与存储结构可不一致,用数组实现程序更方便。此外,作者反思之前目标未达成,将深入学习stl及源码,还计划进一步阅读《高质量C++编程指南》。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

特殊的树

  1. 二叉排序树(二叉查找树/二叉搜索树):若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树
  2. 最小堆:是一种经过排序的完全二叉树,其中任一非终端节点的数据值均不大于其左子节点和右子节点的值
  3. 哈夫曼树(最优二叉树):给定n个权值作为n个叶子结点,构造一棵二叉树,该树的带权路径长度达到最小。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。

    深入虎穴

    实践课上进行了一道难题的讲解,心得如下
    点击跳转:深深深深深深入虎穴

    树的同构

    因为偷懒就把思路写在注释里了,所以就直接贴上来

/*
主要思路是利用递归对两个树进行判断
对于这两棵树,有两个对应子树是同构的,两棵树不一定是同构的
但有两个对应子树不是同构的,两棵树就一定不是同构的
所以在递归过程中,只要出现不同构,就可以退出,判断不同构的
如果是同构,则继续递归进行比较
需要对以下情况进行判断:
1. 两棵树为空:同构
2. 空树和非空树:不同构
3. 两棵树根不同:不同构
由于我们先从左子树判断,所以先对左结点分析
4. 左结点为空:比较右结点
5. 左结点不为空:当两棵树左结点相同时,分别比较两棵树的左子树和右子树是否相同
以上都是对两棵树的结点是否相同进行的判断,也就判断两棵树各个结点是否相等
还没有进行是否同构的判断。要怎么判断是否同构呢?
同构是左右结点互换形成的,本质上是判断一棵树的左结点是否和另一颗树的右结点是否相等
因此当树不相同时(不是4、5),要对左右结点进行判断
*/

#include <iostream>

using namespace std;

//结点定义
typedef struct node {
    char name;
    char lchild;
    char rchild;
}Tree;

int create(Tree tree[], int n);
bool isSame(Tree tree1[], Tree tree2[], int root1, int root2);

int main() {
    int m, n, root1, root2;
    bool result = false;
    Tree tree1[10], tree2[10];
    cin >> m;
    root1 = create(tree1, m);
    cin >> n;
    root2 = create(tree2, n);
    if (m != n) {   //结点数目不相等则不同构
        result = false;
    }
    else if (m == 0 && n == 0) {    //两颗空树为同构
        result = true;
    }
    else if (isSame(tree1, tree2, root1, root2)) {
        result = true;
    }

    if (result) {
        cout << "Yes";
    }
    else {
        cout << "No";
    }
    return 0;
}

//输入,同时得到根结点下标
int create(Tree tree[], int n) {
    int a[10] = { 0 };  //用来记录作为输入中作为叶子结点出现的结点从而得到根结点
    int result = 0;
    if (n == 0) {   //空表,避免野指针
        tree = NULL;
    }
    else {      //输入结点构建树
        for (int i = 0; i < n; i++) {
            cin >> tree[i].name >> tree[i].lchild >> tree[i].rchild;
            if (tree[i].lchild != '-') {
                a[tree[i].lchild - '0'] = 1;
            }
            if (tree[i].rchild != '-') {
                a[tree[i].rchild - '0'] = 1;
            }
        }
        //循环得出根结点
        for (int i = 0; i < n; i++) {
            if (a[i] == 0) {
                result = i;
                break;
            }
        }
    }
    return result;
}

bool isSame(Tree tree1[], Tree tree2[], int root1, int root2) {
    //子树为空
    if ( root1 == '-' - '0' && root2 == '-' - '0') {    
        return true;
    }
    //空树和非空树
    if ((root1 == '-' - '0' && root2 != '-' - '0') && (root1 != '-' - '0' && root2 == '-' - '0')) {
        return false;
    }
    //根结点不同
    if (tree1[root1].name != tree2[root2].name) {
        return false;
    }
    //左子树为空,比较右子树
    if (tree1[root1].lchild == '-'&&tree2[root2].lchild == '-') {
        return isSame(tree1, tree2, tree1[root1].rchild - '0', tree2[root2].rchild - '0');
    }
    //左子树相同
    if ((tree1[root1].lchild != '-'&&tree2[root2].lchild != '-') && (tree1[tree1[root1].lchild - '0'].name == tree2[tree2[root2].lchild - '0'].name)) {
        return isSame(tree1, tree2, tree1[root1].lchild - '0', tree2[root2].lchild - '0') && isSame(tree1, tree2, tree1[root1].rchild - '0', tree2[root2].rchild - '0');
    }
    else {      //比较左右、右左子树
        return isSame(tree1, tree2, tree1[root1].lchild - '0', tree2[root2].rchild - '0') && isSame(tree1, tree2, tree1[root1].rchild - '0', tree2[root2].lchild - '0');
    }
}

心得与目标

让我印象最深的还是树的逻辑结构与存储结构不必一致。很多情况下可以用数组而非二叉链表,会让程序的实现方便很多。
比较遗憾的是之前的目标没有很好地达成,没有很好地学习stl或者阅读其源码,虽然对、和基本的操作都有涉及,但不应该仅仅停留于“我会用”的境地,而应该要知道“为什么这么用”。因此将其拟定为这次目标。相对的,我阅读了《高质量C++编程指南》,受到了比较大的触动(前言比正文好看)。我自认为我的编程习惯很好,却还是有很多不足的地方,令人惭愧。因此对这本书还打算有进一步的阅读。

posted on 2019-05-04 16:50 BlackDn 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/luoyang0515/p/10808940.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值