第5章学习小结
一
学习小结
第5章学习树和二叉树
树
1.树的结构定义是一个递归定义:树的定义中又用到树的定义
2.结点的度即为结点的分支数,树的度是树内各结点度的最大值,二叉树每个结点至多只有两颗子树(即二叉树中不存在度大于2的结点)
二叉树
1.二叉树的子树有左右之分,次序不能颠倒
2. Ⅰ 深度为k的二叉树至多有2^k-1个结点(每层2^(i-1)个,用等比数列求和公式得出结果)
Ⅱ n0=n2+1 证明
其中—— 终端结点数:n0 度为1的结点数:n1 度为2的结点数:n2 结点总数:n 分支总数:B
n = n0 + n1 + n2 ①
n = B + 1 ② //每个结点都对应有一个分支在脑袋上 以及一个根结点
B = n1 + 2 n2 ③ //分支由度为1或2的结点射出
由②③得 n = n1 + 2 n2 + 1 ④
由①④证得 n0=n2+1
Ⅲ 具有n个结点的完全二叉树的深度为 k=⌊log2(n)⌋ + 1
3.顺序存储二叉树,数组的下标可以从1开始。当为完全二叉树时,父子结点的下标关系为 左孩子 = 父*2 右孩子 = 父*2 + 1;缺点:不利于增删 只适用于完全二叉树,否则空间浪费
4.链式存储二叉树
//-----二叉树的二叉链表存储表示----- typedef struct BiTNode { TElemType data; //结点数据域 struct BiTNode *lchild,*rchild; //左右孩子指针 }BiTNode,*BiTree;
5.基于二叉链表的层次遍历
void level(BiTree t) { queue<BiTree> q; BiTree p; q.push(t); while(!q.empty()) { p=q.front(); q.pop(); if(p!=NULL) { cout<<p->data<<" "; q.push(p->lchild); q.push(p->rchild); } } }
层次遍历是这一章我觉得最神奇的地方,不仅更符合实际应用,而且利用了之前学习的队的“先进先出”,实现层次遍历
6.第二神奇的递归——中序遍历的递归算法
void InorderTraverse(BiTree T) {//中序遍历二叉树T的递归算法 if(T) //若二叉树非空 { InorderTraverse(T->lchild);//中序遍历左子树 cout<<T->data<<" "; //访问根节点 InorderTraverse(T->rchild);//中序遍历右子树 } }
7.输入所有结点信息,并得出根结点所在的下标,利用bool类型的数组,是有双亲结点的结点对应在vi数组中置为true,最后寻找唯一一个为false的下标
int input(node *a,int n) { bool *vi; vi=new bool[n]; //vi数组用于找根,下标未出现在输入数据的左右孩子中,则为根 for(int i=0;i<n;++i) { vi[i]=false; //初始化vi数组的全部元素为false } for(int i=0;i<n;++i) { char left,right; cin>>a[i].data; cin>>left; if(left=='-') //若左孩子为空,则将左孩子赋值为-1 { a[i].lchild=-1; } else { a[i].lchild=left-'0'; vi[a[i].lchild]=true; } cin>>right; if(right=='-') //若右孩子为空,则将右孩子赋值为-1 { a[i].rchild=-1; } else { a[i].rchild=right-'0'; vi[a[i].rchild]=true; } } for(int i=0;i<n;++i) //找到根节点所在的下标 { if(!vi[i]) return i; } }
8.哈夫曼树的构造
在森林中选两棵根节点权值最小的树作为左右子树构造一颗新的二叉树,新根的权值为左右子树根结点的和,在森林中删除这两棵树,重复操作
二
关于上次确定的目标及接下来的目标
这两周在代码上花了很多时间,虽然本质上是因为水平不够,导致打代码效率低下(; ̄д ̄) 但是相较之前,我觉得我的学习态度好了很多,起码愿意花时间在上面,虽然有时候磕头破血流,但还是挺有成就感的੭ ᐕ)੭*⁾⁾
接下来希望在保证足够练习的情况下,根据之前的经验教训,提高效率