第五章学习小结

第五章学习小结

一、学习心得

这是第五章的思维导图,本章的重点内容在于二叉树的性质、存储结构、遍历二叉树以及哈夫曼树,我觉得这些内容比较好理解,但是对于哈夫曼树的构造算法的掌握还是不够熟练,应当进一步加强。

二、题目

(1)List Leaves 

这道题的目的是求叶子结点,我的方法是采用队列的方法实现层次遍历。

 1 #include<iostream>
 2 #include<queue>
 3 
 4 using namespace std;
 5 
 6 typedef int Tree;
 7 struct TreeNode
 8 {
 9     Tree Left;
10     Tree Right;
11 }T[10];
12 int N,check[10]={0},count=0;
13 queue<int> q;
14 
15 Tree BuildTree(struct TreeNode T[])
16 {
17     Tree Root=-1;
18     int i;
19     char lch,rch;
20     cin>>N;
21     if(N)
22     {
23         for(i=0;i<N;i++)
24         {
25             cin>>lch>>rch;
26             if(lch!='-')
27             {
28                 T[i].Left=lch-'0';
29                 check[T[i].Left]=1;
30             }
31             else T[i].Left=-1;
32             if(rch!='-')
33             {
34                 T[i].Right=rch-'0';
35                 check[T[i].Right]=1;
36             }
37             else T[i].Right=-1;
38         }   
39         for(i=0;i<N;i++)
40             if(check[i]==0) break;
41         Root=i;
42     }
43     return Root;
44 }
45 
46 void countleaves(Tree Root)//每碰到一个节点将它的左右孩子入队(若有的话),然后依次从队头取出判断是否为叶子节点
47 {        
48     Tree temp;
49     if(Root==-1)  return;
50     q.push(Root);               
51     while(!q.empty())
52     {
53         temp=q.front();
54         q.pop();
55         if(T[temp].Left==-1&&T[temp].Right==-1)//如果没有左右孩子即为叶子节点,则输出
56         {    
57             if(count++!=0)//不是第一个叶子节点的话前面输出空格
58             {     
59                 cout<<' ';
60             }
61             cout<<temp;          
62         }
63         if(T[temp].Left!=-1)      q.push(T[temp].Left);
64         if(T[temp].Right!=-1)     q.push(T[temp].Right);
65     }
66 }
67 int main()
68 {
69     Tree R;
70     R=BuildTree(T);
71     countleaves(R);
72     return 0;
73 }

(2)深入虎穴

这道题是运用到了构造动态数组的方法

 1 #include<iostream>
 2 #include<queue>
 3 using namespace std;
 4 typedef struct
 5 {
 6     int doors;//门的数量
 7     int *p;//p指向具体门的编号,把p看作一个整型数组 
 8 }node;
 9 
10 int input(node *&a);
11 int find(node *a,int);
12 
13 int main()
14 {
15     node *a;//定义一个动态的整型数组
16     int i,j,root;
17     root=input(a);//输入
18     cout<<find(a,root)<<endl;//输出 
19     return 0;
20 } 
21 
22 int input(node *&a)
23 {
24     int n,x,i,j;
25     bool *vi;//用于判断根 
26     cin>>n;
27     a=new node[n+1];//为a数组申请空间 
28     vi=new bool[n+1];//为vi数组申请空间 
29     for(i=1;i<=n;i++)//将vi数组初始化为false 
30      vi[i]=false;
31     for(i=1;i<=n;++i)
32     {
33         cin>>x;
34         a[i].doors=x;
35         a[i].p=new int [x];//有效下标是0~x-1 
36         for(j=0;j<x;++j)
37         {
38             cin>>a[i].p[j];
39             vi[a[i].p[j]]=true;
40         }    
41 }
42     for(i=1;i<=n;++i)
43      if(!vi[i])break;
44     return i; //找出根在a数组的下标
45 }
46 int find(node *a,int root)//从a数组的root下标开始往下搜索 
47 {
48     int x,i;
49     queue<int>q;//定义用于存放带访问的门的编号的队列
50     q.push(root);//根编号入队
51     while(!q.empty())
52     {
53      x=q.front();
54         q.pop();
55         for(i=0;i<a[x].doors;++i)
56          q.push(a[x].p[i]);
57     }//当队列不为空,x=出队,x后面的门的号码入队,答案就是x 
58     return x;
59 }

(3)树的同构

这道题是我做了很久的一道题,思路是用数组存储树,通过下标访问数组的方式得到它的左右子树。最难的地方在于如何判断两棵树是否同构,首先要找到它的根节点才能进行比较,从输入的数据题目的图可以发现根节点是没有结点指向它的,即输入的数据中不会出现根结点,所以我们用check数组保存所有结点的指向(下标)置为0,每次从输入中获取到指向后,将指向的数组位置置为1,最后没有被指到的位置的节点即为根结点。

 

 1 #include<iostream>
 2 using namespace std;
 3 typedef char ElementType;
 4 typedef int Tree;
 5 struct TreeNode
 6 {    
 7     ElementType Data;
 8     Tree Left;
 9     Tree Right;
10 }T1[10],T2[10];
11 int N,check[10];//check数组用于寻找树的根节点
12 
13 Tree BuildTree(struct TreeNode T[])
14 {
15     int Root=-1,i;//刚开始将节点置为空,若为空树的时候可返回-1
16     char cl,cr;
17     cin>>N; 
18     if(N)//如果不为空树的话
19     {              
20         for(i=0;i<N;i++) check[i]=0;//将check数组置为0
21         for(i=0;i<N;i++)
22         {
23             cin>>T[i].Data>>cl>>cr;
24             if(cl!='-')
25             {
26                 T[i].Left=cl-'0';
27                 check[T[i].Left]=1;
28             }
29             else                    
30                 T[i].Left=-1; 
31 
32             if(cr!='-')
33             {
34                 T[i].Right=cr-'0';
35                 check[T[i].Right]=1;
36             }
37             else 
38                 T[i].Right=-1;
39 
40         }
41         for(i=0;i<N;i++)
42             if(!check[i])   break;
43         Root=i;
44     }
45     return Root; 
46 }
47 int compare(Tree R1,Tree R2)
48 {
49     if((R1==-1)&&(R2==-1))//如果为空树则是同构的
50         return 1;
51     if(((R1==-1)&&(R2!=-1))||((R1!=-1)&&(R2==-1)))//如果一个为空一个不为空则不是同构的
52         return 0;
53     if((T1[R1].Data)!=(T2[R2].Data))//如果数据不同则不是同构的
54         return 0;
55     if((T1[R1].Left==-1)&&(T2[R2].Left==-1))//如果左儿子都为空判断右儿子是否同构:主要看以上三个方面(1)右儿子是否都为空(2)是否一个有右儿子一个没有(3)右儿子数据是否相同
56         return compare(T1[R1].Right,T2[R2].Right);//如果两棵树左儿子都不为空并且数据还是一样的,对左儿子进行递归
57     if ( ((T1[R1].Left!=-1)&&(T2[R2].Left!=-1))&&((T1[T1[R1].Left].Data)==(T2[T2[R2].Left].Data)) )
58         return ( compare( T1[R1].Left, T2[R2].Left )&&compare( T1[R1].Right, T2[R2].Right ) );// 如果两棵树左儿子(一个空一个不空或者都不空)并且数据不一样,那么判断第一棵树的左(右)儿子是否跟第二棵树的右(左)儿子同构 
59     else 
60         return ( compare( T1[R1].Left, T2[R2].Right)&&compare( T1[R1].Right, T2[R2].Left ) );
61 
62 }
63 int main()
64 {
65     Tree R1,R2;
66     R1=BuildTree(T1);
67     R2=BuildTree(T2);
68     if(compare(R1,R2))   //compare函数判断是否同构
69         cout<<"Yes";
70     else cout<<"No";
71     return 0;
72 }

 

三、目标达成

上次定下的目标是多多巩固所学知识,多多实践。这一段时间我虽然比较忙,但是依然抽出时间进行了反思,每一次的反思都会有不同的收获,每一次重新回顾之前学过的知识,都会有新的进步。本次的目标是多多巩固树的相关知识,特别是二叉树和哈夫曼树。

 

posted @ 2019-05-04 19:13  带我去喝冰可乐  阅读(161)  评论(1编辑  收藏  举报