第五章学习小结
第五章学习小结
一、学习心得
这是第五章的思维导图,本章的重点内容在于二叉树的性质、存储结构、遍历二叉树以及哈夫曼树,我觉得这些内容比较好理解,但是对于哈夫曼树的构造算法的掌握还是不够熟练,应当进一步加强。
二、题目
(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 }
三、目标达成
上次定下的目标是多多巩固所学知识,多多实践。这一段时间我虽然比较忙,但是依然抽出时间进行了反思,每一次的反思都会有不同的收获,每一次重新回顾之前学过的知识,都会有新的进步。本次的目标是多多巩固树的相关知识,特别是二叉树和哈夫曼树。