• 第五章学习小结


    一、本章内容小结

    本章学习了树和二叉树。重点学习了二叉树的遍历算法还有哈夫曼树,二叉树的遍历算法的作用不单单是遍历,它是树结构插入、删除、修改、查找和排序运算的前提,是二叉树一切运算的基础和核心。

    1.树:包括空树和非空树,包括三种存储结构:双亲表示法、孩子表示法、孩子兄弟表示法(应用较为普遍);还学习了森林和二叉树的转换。

    树的基本术语包括结点、结点的度:分支的个数,树的度:树中所有结点的度的最大值,树的深度:数钟叶子结点所在的最大层次,叶子结点、分支结点、孩子结点、兄弟结点和祖先结点等。我觉得结点的度、树的度、树的深度比较容易混淆,而各类表示关系的结点可将树的图形结构看成一张遗传系谱图,各结点间的关系显得很直观。

    2.二叉树----结点的度小于等于2,有5种不同形态,有5个性质,这些性质都可以通过数学计算推导出来;有两种特殊的二叉树:满二叉树(又称完美二叉树)、完全二叉树,我觉得可以用它们结点的度加以区分。

    存储结构:顺序存储:适用于不需要修改的完全二叉树,而链式存储的适用范围较广,结构如下:

     1 //二叉链表
     2 typedef struct BiTNode
     3 {
     4     TElemType data;
     5     struct BiTNode *lchild, *rchild;      
     6 }BiTNode, *BiTree;
     7 
     8 //三叉链表
     9 typedef struct TriTNode
    10 {
    11     TElemType data;
    12     struct TriTNode *lchid, *parent, *rchild;
    13 }TriTNode, *TriTree;

    先左后右的二叉树遍历算法:先(根)序遍历算法、中(根)序遍历算法、后(根)序遍历算法,其代码实现有两种:

    递归算法:

     1 //先序遍历
     2 void PreOrderTraverse(BiTree T)
     3 {
     4     if(T)
     5     {
     6         cout<<T->data;
     7         PreOrderTraverse(T->lchild);
     8         PreOrderTraverse(T->rchild);
     9     }
    10 }
    11 
    12 //中序遍历
    13 void InOrderTraverse(BiTree T)
    14 {
    15     if(T)
    16     {
    17         InOrderTraverse(T->lchild);
    18         cout<<T->data;
    19         InOrderTraverse(T->rchild);
    20     }
    21 }
    22 
    23 //后序遍历
    24 void PostOrderTraverse(BiTree T)
    25 {
    26     if(T)
    27     {
    28         PostOrderTraverse(T->lchild);
    29         PostOrderTraverse(T->rchild);
    30         cout<<T->data;
    31     }
    32 }

    迭代算法:

     1 //先序遍历
     2 void PreOrderIteration(BiTree T)
     3 {
     4     stack<BiTree> s;
     5     BiTree p;
     6     if(T!=NULL)   s.push(T);
     7     while(!s.empty())
     8     {
     9         p=s.top();
    10         s.pop();
    11         cout<<p->data<<" ";
    12         if(p->rchild!=NULL)  s.push(p->rchild);
    13         if(p->lchild!=NULL)  s.push(p->lchild);
    14     }
    15 } 
    16 
    17 //中序遍历
    18 void InOrderIteration(BiTree T)
    19 {
    20     stack<BiTree> s;
    21     BiTree p=T;
    22     while(p!=NULL || !s.empty())
    23     {
    24         while(p!=NULL)//一直走到左尽头 
    25         {
    26             s.push(p); //期间结点入栈 
    27             p=p->lchild;
    28         }
    29         p=s.top();  //左已访问右未访问 
    30         s.pop();
    31         cout<<p-data<<" ";
    32         p=p->rchild;  //准备遍历右子树 
    33     }    
    34 } 

    个人觉得递归算法比迭代算法更易于理解,而且这两种算法的时间复杂度都为O(n),时间复杂度也都为O(n)。但迭代算法在一些方面也有优势,其运用了栈和队列的思想,而第五章pta的实践1的List Leave就运用了队列的思想。

    二叉树遍历算法的应用举例:

     1 //先序建立二叉树
     2 void CreateBiTree(BiTree &T)
     3 {
     4     cin>>ch;
     5     if(ch=='#')   T=NULL;
     6     else
     7     {
     8         T=new BiTNode;
     9         T->data=ch;
    10         CreateBiTree(T->lchild);
    11         CreateBiTree(T->rchild);
    12     }
    13 }
    14 
    15 //先序复制二叉树
    16 void Copy(BiTree T, BiTree &NewT)
    17 {
    18     if(T==NULL)
    19     {
    20         NewT=NULL;  return;
    21     }
    22     else
    23     {
    24         NewT=new BiTNode;
    25         NewT->data=T->data;
    26         Copy(T->lchild,NewT->lchild);
    27         Copy(T->rchild,NewT->rchild);    
    28     }
    29 }
    30 
    31 //计算二叉树深度
    32 int Depth(BiTree T)
    33 {
    34     if(T=NULL)  return 0;
    35     else
    36     {
    37         DepthLeft=Depth(T->lchild);    
    38         DepthRight=Depth(T->rchild);    
    39         return(1+max(DepthLeft,DeptjRight));
    40     } 
    41 }
    42  
    43 //计算二叉树结点总数 
    44 int NodeCount(BiTree T)
    45 {
    46     if(T=NULL)  return 0;
    47     else
    48     {
    49         return     NodeCount(T->lchild)+NodeCount(T->rchild)+1;//每一个+1,代表每一个结点!!! 
    50     } 
    51 }

    3.线索二叉树:保存了前驱和后继两个信息,利用了空链域

    1 //二叉树的二叉线索存储定义
    2 typedef struct BiThrNode
    3 {
    4     TElemType data;
    5     struct BiThrNode *lchild, *rchild;
    6     int LTag, RTag;
    7 }BiThrNode, *BiThrTree; 

    通过对标志域LTag和RTag存储数值的判断来决定lchild和rchild域的指向!

    4.哈夫曼树:又称最优树,约定其左分支代表0,右分支代表1,便构造出了哈夫曼编码;哈夫曼树的构造也有一定的方法可循。

    相关概念:路径、路径长度、树的路径长度、权、结点的带权路径长度、树的带权路径长度。

    哈夫曼树的存储表示:

    1 typedef struct
    2 {
    3     int weight;  //结点的权值 
    4     int parent, lchild, rchild;  //结点的双亲、左孩子、右孩子的下标 
    5 }HTNode, *HuffmanTree;   //动态分配数组存储哈夫曼树 

    哈夫曼编码满足两个性质:

    A.哈夫曼编码是前缀编码。

    B.哈夫曼编码是最优前缀编码。

    二、实践心得

    在限时测试时,把层序遍历和先序遍历弄混了,后来也分清了二者的区别。在看过慕课的带你打代码后,能及时地复现出来,但过段时间又会有点模糊,需要定时地回顾一下。打实践1的树的同构时,顺带回顾了typedef struct和struct定义结构体的不同之处,也看了一些博客,https://blog.csdn.net/haiou0/article/details/6877718,这一篇就讲得很细!

  • 相关阅读:
    [bzoj3123] [Sdoi2013]森林
    [bzoj2173] 整数的lqp拆分
    Linux
    使用高德地图API
    EF具体用在什么类型的项目上
    出现Data Tools 与VS 不兼容问题
    Entity FramWork
    Entity
    Entity
    BASH
  • 原文地址:https://www.cnblogs.com/zzssx/p/12979535.html
Copyright © 2020-2023  润新知