第五章学习小结

本章我们学习了树和二叉树。包括树和二叉树的定义,二叉树的性质和存储结构,二叉树的遍历,树和森林,哈夫曼树的构造等。

二叉树的性质有三个: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<T.Num[i].cnum;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<int> Q; int k;

        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<T.Num[k].cnum;i++) {//遍历编号为k的孩子结点,并将他们一一入队

                               Q.push(T.Num[k].next[i]);

                     }

              }

      }

cout << k <<endl;//循环结束时,k应为最深的叶子结点的编号

}

但是还是不太明白这个check数组是怎么用的。。

下阶段目标:认真完成学习讨论的任务,作业不拖ddl,做好课堂小结。

 

posted @ 2020-05-31 21:21  木兮远修  阅读(204)  评论(0编辑  收藏  举报