第五章随笔小结
第五章是大名鼎鼎的树,学的怎么说呢。。。
原理不难,操作啊,遍历啊,查找删除啥的也都基本掌握了。就感觉现在思维很难拓展发散开,像哈夫曼树感觉真是太神奇了。
还是先捋一下学了啥吧
首先存储还是借助线性工具来存储这种非线性的东西,主要通过数组下标啊,链表啊某种逻辑来实现树结点之间的链接。一般有1.双亲表示法2.孩子表示法3.孩子兄弟法。。。当然兵无常势,水无常形,表示法还有很多,需要自己在解决问题过程中选择合理的方法
然后遍历则有先、中、后、层次遍历四种遍历
先
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
void PreOrderTravel(node t[], int x) {//先序遍历t[x]为根结点的树t cout << t[x].name << " "; if(t[x].lch!=-1) PreOrderTravel(t, t[x].lch); if(t[x].rch!=-1) PreOrderTravel(t, t[x].rch); }
中
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
void InOrderTravel(node t[], int x) {//中序遍历t[x]为根结点的树t if(t[x].lch!=-1) InOrderTravel(t, t[x].lch); cout << t[x].name << " "; if(t[x].rch!=-1) InOrderTravel(t, t[x].rch); }
后
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
void PostOrderTravel(node t[], int x) {//后序遍历t[x]为根结点的树t if(t[x].lch!=-1) PostOrderTravel(t, t[x].lch); if(t[x].rch!=-1) PostOrderTravel(t, t[x].rch); cout << t[x].name << " "; }
层次
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
void levelOrderTraverse(node t[], int x) {//层次遍历t[x]为根结点的树t int tmp; queue<int> q; q.push(x); //根结点所在下标入栈 while(!q.empty()){ tmp = q.front(); q.pop(); if(tmp!=-1){ cout << t[tmp].name << " "; q.push(t[tmp].lch); q.push(t[tmp].rch); } } }
基于此可以解决许多问题。。。讲讲作业
首先是简单的遍历查找了,就是题目读了半天
Given a tree, you are supposed to list all the leaves in the order of top down, and left to right.
Input Specification:
Each input file contains one test case. For each case, the first line gives a positive integer N (≤) which is the total number of nodes in the tree -- and hence the nodes are numbered from 0 to N−1. Then N lines follow, each corresponds to a node, and gives the indices of the left and right children of the node. If the child does not exist, a "-" will be put at the position. Any pair of children are separated by a space.
Output Specification:
For each test case, print in one line all the leaves' indices in the order of top down, and left to right. There must be exactly one space between any adjacent numbers, and no extra space at the end of the line.
Sample Input:
8
1 -
- -
0 -
2 7
- -
- -
5 -
4 6
Sample Output:
4 1 5
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<queue> using namespace std; typedef struct { int lch; int rch; }node; int BulidTree(node t[]); void levelOrderTraverse(node t[], int x); //层次遍历 int main() { node t[100]; int x; x = BulidTree(t); levelOrderTraverse(t, x); return 0; } int BulidTree(node t[]) { bool check[100] = { false }; int n; char x, y; cin >> n; for (int i = 0; i < n; i++) { cin >> x >> y; if (x != '-') { t[i].lch = x - '0'; check[t[i].lch] = true; } else t[i].lch = -1; if (y != '-') { t[i].rch = y - '0'; check[t[i].rch] = true; } else t[i].rch = -1; } for (int i = 0; i < n; i++) { if (!check[i]) return i; } } void levelOrderTraverse(node t[], int x) {//层次遍历t[x]为根结点的树t int tmp; int space=-1; queue<int> q; q.push(x); //根结点所在下标入栈 while (!q.empty()) { tmp = q.front(); q.pop(); if (tmp != -1) { if (t[tmp].lch == -1 && t[tmp].rch == -1){ if(space==1) cout<<" "; //处理末尾空格 cout<<tmp; space=1; } q.push(t[tmp].lch); q.push(t[tmp].rch); } } }
没啥好说的。。。
然后又是一道天梯题,难度倒是还可以
著名的王牌间谍 007 需要执行一次任务,获取敌方的机密情报。已知情报藏在一个地下迷宫里,迷宫只有一个入口,里面有很多条通路,每条路通向一扇门。每一扇门背后或者是一个房间,或者又有很多条路,同样是每条路通向一扇门…… 他的手里有一张表格,是其他间谍帮他收集到的情报,他们记下了每扇门的编号,以及这扇门背后的每一条通路所到达的门的编号。007 发现不存在两条路通向同一扇门。
内线告诉他,情报就藏在迷宫的最深处。但是这个迷宫太大了,他需要你的帮助 —— 请编程帮他找出距离入口最远的那扇门。
输入格式:
输入首先在一行中给出正整数 N(<),是门的数量。最后 N 行,第 i 行(1)按以下格式描述编号为 i 的那扇门背后能通向的门:
K D[1] D[2] ... D[K]
其中 K
是通道的数量,其后是每扇门的编号。
输出格式:
在一行中输出距离入口最远的那扇门的编号。题目保证这样的结果是唯一的。
输入样例:
13
3 2 3 4
2 5 6
1 7
1 8
1 9
0
2 11 10
1 13
0
0
1 12
0
0
输出样例:
12
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<queue> using namespace std; typedef struct{ int doors;//门的数量 int *p;//指向的门的编号序列 }node; int input(node *,int ); int level(node *,int ); int main(){ node *a; //用于存储整棵树 int n,root; cin>>n; a=new node[n+1]; root = input(a, n); //输入,找根 cout << level(a, root); //参差遍历 return 0; } int input(node *a,int n){ //读入n扇门的信息给a数组,返回根所在的门牌号 int i,j; bool *vi; vi=new bool[n+1]; for(int i=1;i<=n;i++){ //初始化vi数组的全部元素为false vi[i]=false; } for(int i=1;i<=n;i++){ cin>>a[i].doors; if(a[i].doors!=0){ a[i].p=new int[a[i].doors]; //申请门的空间 for(int j=0;j<a[i].doors;j++){ cin>>a[i].p[j]; vi[a[i].p[j]]=true; } } else a[i].p=NULL; //doors为0 } //读入n扇门的信息 for(int i=1;i<=n;i++){ if(vi[i]!=true) return i; } } int level(node *a,int r){ queue<int> q; int t,i; q.push(r); while(!q.empty()){ t=q.front(); q.pop(); if(a[t].doors!=0){ //t号门后还有门,后面的门入队 for(int i=0;i<a[t].doors;++i){ q.push(a[t].p[i]); } } } return t; }
感觉首先思路一定不能乱,对于这种较复杂的题注意把控好自己的操作和思维以及写出来代码的目的
其次对于数组下标的对应,越界,内存分配需要有一种野兽般的直觉,当然这点要多多练习。。。
上一章讲的思维线还在整合。。。看来要多找点题刷一刷了。新的目标是把自己的思维要发散开,不能打代码时思维太过僵硬或者总是拓展不开来。。。