第五章我们学习了新的数据结构,也就是树。相比较与之前学的内容,我觉得树更加的复杂。
在学习二叉树的遍历的过程中,在树的操作过程中很多重复操作都是要通过递归实现的,我对递归的思想也更加深刻明了。
我们也学习了许多二叉树的性质,比如:
二叉树的性质:
1:二叉树的第i层上至多有2^(i-1)个结点
2:深度为k的二叉树,至多有2^k-1个结点
完全二叉树的性质:
1:结点 i 的子结点为2*i 和 2*i+1(前提是都小于总结点数)
2:结点 i 的父结点为 i/2
还学习了遍历二叉树的3中方法:
1:先序遍历:根->左子树->右子树
2:中序遍历:左子树->根->右子树
3:后序遍历:左子树->右子树->根
二叉树的储存结构有:链式结构(采用链表法),顺序结构(采用数组),个人使用感觉顺序结构更加的方便
也学习了霍夫曼树的构建与计算:
(1)将各个节点按照权重从小到大排序;
(2)取最小权重的两个节点,并新建一个父节点作为这两个节点的双亲,双亲节点的权重为子节点权重之和,再将此父节点放入原来的队列;
(3)重复(2)的步骤,直到队列中只有一个节点,此节点为根节点;
在小组合作中,我们组一开始的代码如下:
#include<iostream> using namespace std; typedef struct {//定义叶子结点 int parent=-1;//记录每个结点的父节点 int k=0;//判断是否为叶子结点 }Node; typedef struct {//定义树结构 Node data[100001]; int root;//root记录根节点 }*tree, Tree; void creattree(tree& T, int n)//构建树 { int m, a, b[100001] = { 0 }; for (int i = 1; i <= n; i++) { cin >> m; if (m == 0)//判断是否为叶子结点 T->data[i].k = 1; else for (int k = 0; k < m; k++) { cin >> a; T->data[a].parent = i; b[a]=1; } } for (int i = 1; i <= n; i++)//遍历查找根结点 if (b[i] == 0) { T->root = i; T->data[i].parent = -1; break; } } void searchleaf(tree T, int n)//查找最深的结点 { int k = 0, m = 0, M = 0; for (int i = 1; i <= n; i++) { if (T->data[i].k == 1)//判断是否为叶子结点 { int a = i; while (T->data[a].parent != -1)//向上循环直到根节点 { k++; a = T->data[a].parent; } if (k == n - 1)//判断k是否到达结点深度最大值 { M = i; break; } else if (k > m) { M = i; m = k; } } k = 0; } cout << M; } int main() { tree T = new Tree; int n; cin >> n; creattree(T, n); if (n == 1) cout << 1; else searchleaf(T, n); }
有以下问题:
1.最后一个测试点会出现时间超时
2.算法是由叶子结点向上查找根节点,比较深度,时间复杂度太大
3.没有释放空间
因为算法出了问题,导致整个代码都无法过关,后来尝试了许多改进比如构造一个数组记录叶子结点,也无法过最后一个测试点。叶子结点向上查找根节点的算法在查找叶子深度的方面时间复杂度是O(n^2),而层次遍历是O(n)。
以后小组展开工作前应吸取这次的教训,仔细讨论出方法的时间复杂度再开工,以免出现这种问题。
原文:https://www.cnblogs.com/GJJbk/p/13021113.html