• 第五章学习小结


    特殊的树

    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++编程指南》,受到了比较大的触动(前言比正文好看)。我自认为我的编程习惯很好,却还是有很多不足的地方,令人惭愧。因此对这本书还打算有进一步的阅读。

  • 相关阅读:
    WP7开发学习(3):在WP7中使用WCF+log4net 打印并输出日志文件(附源码)
    MongoDB开发学习(2)索引的基本操作
    C#批量添加水印
    获取某一时间戳的月份的开始时间戳和结束时间戳
    php判断一个字符串是否为日期格式
    正则表达式匹配括号引号内容
    PHP获取今日汽油价格接口
    ThinkPHP5 在Nginx环境下开启伪静态
    PHP格式化打印:JSON字符串|对象|数组
    php header ContentType出错
  • 原文地址:https://www.cnblogs.com/luoyang0515/p/10808940.html
Copyright © 2020-2023  润新知