数据结构学习-第二次总结
互评作业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);
}
}