• 第五章学习小结


    树和二叉树

    定义概念不再赘述,需要注意的一些地方:

    1.树的其他表示方式

    2.重点研究二叉树的原因

    二叉树的结构最简单,规律性最强;

    可以证明,所有树都能转为唯一对应的二叉树,不失一般性;

    普通树转化为二叉树后,运算容易实现。

    3.二叉树的性质

    在二叉树的第i层上至多有2i-1个结点。

    深度为k的二叉树上至多含2k - 1个结点(k≥1)。

    对任何一棵二叉树,若它含有n0个叶子结点、n2个度为2的结点,则必存在关系式:n0 = n2 + 1。

    具有n个结点的完全二叉树的深度为 (log2n) +1 。

    对完全二叉树,若从上至下、从左至右编号,则编号为 i 的结点,其左孩子编号必为2i,其右孩子编号必为2i+1;其双亲的编号必为i/2。

    4.森林与二叉树的互相转换

    5.哈夫曼树的构造

    在森林中选取两棵根结点权值最小的树作左右子树,构造一棵新的二叉树,置新二叉树根结点权值为其左右子树根结点权值之和。

    在森林中删除这两棵树,同时将新得到的二叉树加入森林中。

    重复上述两步,直到只含一棵树为止,这棵树即哈夫曼树。

    习题

    1.深入虎穴

     1 #include<iostream>
     2 #include<queue> 
     3 using namespace std;
     4 
     5 typedef struct
     6 {
     7     int doors;                //门的数量
     8     int *p;                   // 指向具体门的编号,把p看作一个整型数组 
     9 }node; 
    10 
    11 int input(node *&a);
    12 int find(node *a,int root);
    13 
    14 int main()
    15 {
    16     //变量的定义
    17     node *a;                      //定义一个动态整型数组 
    18     int root;                     
    19     root=input(a);
    20     cout<<find(a,root)<<endl;
    21     
    22     return 0;
    23  } 
    24  
    25  int input(node *&a)
    26  {
    27      int n,x,i,j,k;
    28      bool *vi;
    29      cin >> n;
    30      a = new node[n+1];     //为a数组申请空间
    31      vi= new bool[n+1];     //同上 
    32      for(i=1;i<=n;i++)      //将vi数组初始化为false 
    33      {
    34       vi[i]=false;
    35      } 
    36      for(i=1;i<=n;++i)
    37      {
    38          cin>>x;
    39          a[i].doors=x;    
    40          a[i].p=new int[x];
    41          for(j=0;j<x;++j)
    42             {
    43             cin>>a[i].p[j];
    44              vi[a[i].p[j]] =true;
    45             } 
    46     } 
    47     for (k=1;k<=n;k++)      //找出根在a数组的小标
    48     {
    49         if(!vi[k]) break;
    50     
    51     }     
    52     return k;
    53  }
    54 int find(node *a,int root)
    55 {
    56      int x;
    57      int i;
    58      queue<int> q;          //定义用于待访问的门编号的队列 
    59      q.push(root);
    60      while(!q.empty())
    61      {
    62          x=q.front();
    63          q.pop();
    64          for(i=0;i<a[x].doors;++i)
    65          {
    66          q.push(a[x].p[i]);
    67         }
    68      }
    69      return x;
    70 }
    View Code

    需要注意的是,题目并没有给出根节点,需要在循环体中找出根所在数组的下标;

    老师还介绍了STL中队列的使用方法,可以省去建立队列的麻烦,但这并不代表我们不需要了解底层的实现方法;

    #include<queue>
    queue<int> q;
    2.List Leaves
     1 #include<iostream>
     2 using namespace std;
     3  
     4 int n ;
     5 bool jud[20];
     6 struct node{
     7     int lchild;    
     8     int rchild;    
     9 }tree[20];       //定义一个树的结构体; 
    10  int s[20];      //用来存树的信息; 
    11  int head = 0 , rear = 0;       //用来输出叶子结点的序号; 
    12  int main()
    13  {
    14      cin>>n;
    15      char l , r;
    16      for(int i = 0 ; i < n ;i++)
    17      {
    18          cin>>l>>r;
    19          if(l!='-') 
    20          {
    21              tree[i].lchild = l - '0';    
    22              jud[tree[i].lchild] = 1;     //标记这个数字是i的左的孩子; 
    23          }else
    24         {
    25             tree[i].lchild = -1;          //否则i没有左孩子,将其置为-1; 
    26          }
    27      
    28          if(r!='-')           
    29          {
    30              tree[i].rchild = r - '0';
    31              jud[tree[i].rchild] = 1;      //标记这个数字是i的右的孩子; 
    32          }else
    33          {
    34              tree[i].rchild = -1;
    35          }
    36      }
    37      int root;
    38          for(int i = 0 ; i < n ;i++)
    39      {
    40           if(jud[i]==0)      //如果i不是孩子,则它是根结点; 
    41           {
    42             root = i ;
    43               break;
    44           }
    45      }
    46      int leaves = 0;
    47       s[rear++] = root;
    48       while(rear - head > 0 )
    49      {
    50          int num = s[head++];
    51          if (tree[num].lchild == -1 && tree[num].rchild == -1) {    //既没左孩子也没右孩子,输出叶节点; 
    52  
    53            if (leaves)  
    54             cout<<" ";     
    55 
    56             cout<<num;
    57  
    58             ++leaves;   //若是叶子结点,则叶子结点数目++; 
    59 
    60         }
    61 
    62         if (tree[num].lchild != -1) {        //如果存在,左孩子入队
    63 
    64              s[rear++] = tree[num].lchild;
    65  
    66         }
    67 
    68          if (tree[num].rchild != -1) {        //如果存在,右孩子入队
    69  
    70              s[rear++] = tree[num].rchild;
    71  
    72         }
    73  
    74          
    75      }     
    76     return 0 ;
    77 }
    View Code

    关键点:找到根结点,它不是任意结点的孩子;

                   记录叶子节点的序号,便于输出;

                   建立额外的一个数组来处理树的信息;

    3.树的同构

    给定两棵树T1和T2。如果T1可以通过若干次左右孩子互换就变成T2,则我们称两棵树是“同构”的。例如图1给出的两棵树就是同构的,因为我们把其中一棵树的结点A、B、G的左右孩子互换后,就得到另外一棵树。而图2就不是同构的。

    讲一下图1具体是怎样同构的:

    T1的A结点、B结点、G结点左右孩子互换,得到T2,因此图1是同构的;

    判断是否同构的函数:

     1  Status Isomprphic(int root1, int root2)
     2  {
     3      if( (root1 == -1) && (root2 == -1))                              //都是空 ,同构 
     4          return OK;
     5      if( (root1 == -1)&&(root2 != -1) || (root1 != -1)&&(root2 == -1))//其中一个为空,不同构 
     6          return ERROR;
     7      if(T1[root1].data != T2[root2].data)                             //根不同,不同构 
     8         return ERROR;
     9      if( (T1[root1].left == -1) && (T2[root2].left == -1) )           //左子树为空,则判断右子树 
    10         return Isomprphic(T1[root1].right, T2[root2].right);
    11          
    12     if((T1[root1].left != -1) && (T2[root2].left != -1) &&( T1[T1[root1].left].data == T2[T2[root2].left].data) )//两树左子树皆不空,且值相等 
    13          return (Isomprphic(T1[root1].left, T2[root2].left) && Isomprphic(T1[root1].right, T2[root2].right) ); //判断其子树 
    14          
    15     else                                                                                                      //两树左子树有一个空  或者  皆不空但值不等  
    16         return (Isomprphic(T1[root1].left, T2[root2].right) &&Isomprphic(T1[root1].right, T2[root2].left) );  //交换左右子树判断 
    17         
    18      
    19  }
    View Code
  • 相关阅读:
    HTTP 方法:GET 对比 POST
    【总结整理】关于写前端页面小技巧
    【总结整理】关于IE6的兼容性
    添加制图图例(转)
    【总结整理】JQuery调试
    【总结整理】关于切图
    【总结整理】JQuery小技巧
    【总结整理】webstorm插件使用
    【总结整理】JQuery基础学习---动画
    初学正则表达式
  • 原文地址:https://www.cnblogs.com/gwpsf/p/10808034.html
Copyright © 2020-2023  润新知