本章我们学习了树和二叉树。包括树和二叉树的定义,二叉树的性质和存储结构,二叉树的遍历,树和森林,哈夫曼树的构造等。
二叉树的性质有三个:1)一个二叉树T层的最大结点数为2^(k-1) K>=1
2)一个深度为k的二叉树有最大结点总数为2^k - 1,k>1
3)对任何非空二叉树,n0 = n2 + 1
二叉树的存储结构:1)数组存储。需要将二叉树进行排序,再顺序存储,但是如果存储的二叉树为一般的二叉树,会造成空间浪费。
2)链表存储。用左儿子右兄弟的方式进行存储
二叉树的遍历:1)层次 2)先序 3)中序 4)后序
层次遍历:通过入队和出队一层一层对二叉树进行遍历。
void LevelOver(BiTree T)
{
if (BT != NULL) {
push(q, T); //根节点指针进队列
}
while (emptyQueue(q) != true) { //队不为空循环
pop(q, T); //出队时的节点
cout << T -> data; //输出节点存储的值
if (T -> lchild != NULL) { //有左孩子时将该节点进队列
push(q, T->lchild);
}
if (T -> rchild != NULL) { //有右孩子时将该节点进队列
push(q, T->rchild);
} //一层一层的把节点存入队列
}
}
先序遍历:先访问根节点,再用递归的方法访问最字叔和右子树
void PreOver(BiTree T)
{
if(T){
cout << T -> data; //访问根节点
PreOver(T -> lchild); //遍历左子树
PreOver(T -> rchild); //遍历右子树
}
}
二叉链表的建立:
先序:
void Create(BiTree T)
{
cin >> ch;
if(ch == '#' ) T = NULL;
lese{
T = new BiTNode;
T->data = ch ; //生成根节点
Creat(T->lchild); // 创建左子树
Creat(T->rcjild); //创建右子树
}
树和森林采用左孩子右兄弟的链表存储,从而将森林变为一颗类似于二叉树的树
哈夫曼树一定是最优树,即WPL为最小值,但也存在其他的最优非哈夫曼树(先用哈夫曼树的构造方法算出的WPL值,再根据WPL构造出非哈夫曼树)
分组协作:找出非二叉树的最深叶子结点。印象最深刻的是陈思宇小组的代码,
用动态数组存储孩子结点的编号,用check数组找根节点,再进行层次遍历找出最深的叶子结点。部分代码如下:
void Creat(Tree &T)//内存耗尽,所以加了&
{
int i,j,n;
bool check[100001]={false};//查找根节点
cin >> n;
for(i=1;i<=n;i++) {
cin >> T.Num[i].cnum;
T.Num[i].next = new int[T.Num[i].cnum+1];//为孩子结点数组分配空间
for(j=0;j cin >> T.Num[i].next[j]; check[T.Num[i].next[j]] = true; } } for(i=1;i<=n;i++) {//未出现过的编号就是根节点的编号 if(!check[i]) { T.root = i; break; } } } void LevelOrder(Tree &T) {//层次遍历 queue Q.push(T.root);//根节点的编号入队 int i; while(!Q.empty()) { k = Q.front();//队头元素赋值给 k Q.pop();//队头元素出队 if(T.Num[k].cnum>0) {//编号为k的结点有孩子结点的情况 for(i=0;i Q.push(T.Num[k].next[i]); } } } cout << k < } 但是还是不太明白这个check数组是怎么用的。。 下阶段目标:认真完成学习讨论的任务,作业不拖ddl,做好课堂小结。