这周学习了树和二叉树。
主要就是递归,之前一直不明白递归是什么,通过这几次课我了解的更详细,也体会到了递归的神奇之处。
来记录一些我从课堂上学到了知识吧
二叉树的课堂笔记 1, 返回值,先看函数要干嘛,如果是对内容进行操作类,无需结果回传 2,原型声明,直接copy函数定义那里,只不过形参括号内不用类型定义 Typedef struct Node{//结构体定义,链表的结点定义 ElemType data; Struct node *lchild; Struct node *rchild; }Node,*Bitree;//都是代表二叉树的结点名称,区别就是Node *t之某个结点的指针,Bitree指头指针(或是说根节点) Void PreOrder(Node*/Bitree t)//t是一个根节点 (注意!在定义函数时,括号里的形参要有类型定义) { If(t==NULL) return;(return用法?返回上层? cout << t->data << “ “;(输出根的数据,为什么记录的是用双引号 PreOrder(t->lchild); PreOrder(t->rchild);//用递归造树,(只对本层写正确逻辑,不考虑下层) } //函数说明:左孩子为空时,return退出当前函数,返回上层(递归),进行PreOrder(t->rchild) void create (Bitree &t)//建立一棵空树,t指向根结点 //发现该树传不回去,说明是形参问题,但是t是指针,为什么会传不回去呢?但对t进行操作时,如果改变的是其直接空间,如操作(a),,只改变地址,不改变t的内容,如改变其间接空间,如(a[1],a[2])是不需要&) {//每建立一棵树,先读入,再判断是否#(为空树) ElemType x;//以X作为根结点的树 cin >> x; if (x == ‘#’){//建立一颗空树 t = NULL;//有指针就要赋初值 return ;//强行中止函数执行 } t == new Node;//为t分配像Node结构的空间 //操作的是间接空间 //形参不用再在函数内进行定义!!直接用 t->data = x;//输入根结点x create(t->lchild); create(t->rchild); //一般操作先写主函数架构思路,再不断补充函数的操作 Int main() { Bitree t ==NULL;//结构体Bitree直接用,形参在主函数中定义就够了! create( t );//创造读入树 注意在主函数中引用函数直接写函数名(形参)即可 PreOrder( t );//读出树 return 0; }
以及老师带我们打的深入虎穴的思路
1. 对树进行层次遍历 2. 门的编号1-N 3. 由编号得出可用数组 4. 二维数组表现树的存储关系,符合行号列号置一 5. 第二种 6. 10的5次*10 的5次,考虑稀疏矩 7. 可看为1维数组 8. 存储指针(单链表) 9. 先定义一个结构体(整数加指针) 10. 第二种,指针P后面带了一个数组P【0】,P【1】 11. P指针后面用new申请一个新数组空间
再然后是作业啦,
1 #include<iostream> 2 #include<queue> 3 using namespace std; 4 5 typedef char ElemType; 6 7 typedef struct Node{//结构体定义,链表的结点定义 8 ElemType data; 9 struct Node *lchild; 10 struct Node *rchild; 11 }Node,*Bitree;//都是代表二叉树的结点名称,区别就是Node *t之某个结点的指针,Bitree指头指针(或是说根节点) 12 13 void levelOrderTraverse(Bitree t, int x)//t是一个根节点 //PreOrder函数用于遍历输出 (层次遍历) 14 { 15 queue<int> q; 16 int m; 17 if(t==NULL) return; 18 if(t->lchild == NULL && t->rchild == NULL ) 19 q.push(t->data); 20 while(!q.empty()){ 21 m == q.front(); 22 q.pop(); 23 if(!q.empty()) 24 cout << m <<" "; 25 else cout << m; 26 q.push(t[m].lch);//??t要用数组表示不然表示不出跳到下一个指针的方法 27 q.push(t[m].rch); 28 } 29 //用递归造树,(只对本层写正确逻辑,不考虑下层) 30 } 31 //函数说明:左孩子为空时,return退出当前函数,返回上层(递归),进行PreOrder(t->rchild) 32 33 int BulidTree(Bitree t) 34 { 35 36 37 bool check[100] = {false}; 38 int n; 39 char x, y; 40 41 cin >> n; 42 43 for (int i=0; i<n; i++){ 44 45 cin >> x >> y; 46 47 if(x!='-'){ 48 t->lchild = x-'0'; 49 check[t->lchild] = true; 50 } 51 else 52 t->lchild = -1; 53 54 if(y!='-'){ 55 t->rchild = y-'0'; 56 check[t->rchild] = true; 57 } 58 else 59 t->rchild = -1; 60 } 61 62 for (int i=0; i<n; i++){ 63 if(!check[i]) return i; 64 } 65 } 66 67 /*void create (Bitree &t)//建立一棵树,并读入,t指向根结点 68 {//每建立一棵树,先读入,再判断是否-(为空树)//在输入树时顺便找根结点 69 ElemType x;//以X作为根结点的树 70 cin >> x; 71 if (x == '-'){//根为空 72 t = NULL;//有指针就要赋初值 73 return ;//强行中止函数执行 74 } 75 //x!='-'; 76 t == new Node;//为t分配像Node结构的空间 77 t->data = x-'0';//输入根结点数字x 78 create(t->lchild); 79 create(t->rchild); 80 } 81 */ 82 83 int main() 84 { 85 int x; 86 Bitree t;//不能Bitree t == NULL 87 t == NULL;//结构体Bitree直接用,形参在主函数中定义就够了! 88 //create(t);//创造读入树 注意在主函数中引用函数直接写函数名(形参)即可 89 x == BulidTree(t);//找到根结点 90 levelOrderTraverse(t, x);//读出树 91 return 0; 92 }
这个因为结点用的是指针,所以在如何把左孩子转化为下一个指针的时候出现了问题,暂时还没想到解决的办法,
于是我换成了用数组表示本结点的名字,这样就可以通过i来表示。
1 #include<iostream> 2 #include<queue> 3 4 using namespace std; 5 6 typedef struct{//树结点的类型定义 7 int lch; 8 int rch; 9 }node; 10 11 int BulidTree(node t[]); 12 void levelOrderTraverse(node t[], int x); //层次遍历 13 14 15 int main() 16 { 17 node t[100];//??怎么可以直接node一个数组呢 18 int x; 19 20 x = BulidTree(t);//找出了根节点x 21 levelOrderTraverse(t, x); //水平遍历并输出叶子结点 22 return 0; 23 } 24 25 int BulidTree(node t[])//输入并查找根结点 26 { 27 bool check[100] = {false};//判断根结点的标志 28 int n; 29 char x, y; 30 31 cin >> n; 32 33 for (int i=0; i<n; i++){ 34 35 cin >> x >> y;//输入左孩子和右孩子 36 37 if(x!='-'){//如果孩子不为空 38 t[i].lch = x-'0';//给孩子赋值 39 check[t[i].lch] = true;//标志改为ture 40 } 41 else 42 t[i].lch = -1;//否则孩子为-1 43 44 if(y!='-'){ 45 t[i].rch = y-'0'; 46 check[t[i].rch] = true; 47 } 48 else 49 t[i].rch = -1; 50 } 51 52 for (int i=0; i<n; i++){ 53 if(!check[i]) return i;//返回根结点下标 54 } 55 } 56 57 void levelOrderTraverse(node t[], int x) 58 {//层次遍历t[x]为根结点的树t 59 int tmp; 60 queue<int> q; 61 q.push(x); //根结点所在下标入栈 62 int flag = 0; //用flag做判断第一个输出的指标 63 while(!q.empty()){ 64 tmp = q.front(); //记录队头元素 65 q.pop(); 66 flag++; 67 if(t[tmp].lch==-1 && t[tmp].rch==-1)//如果是叶子结点 ,输出 68 { 69 if(flag == 0) cout << tmp; 70 else cout << " " << tmp; 71 } 72 q.push(t[tmp].lch);//如何做到层次遍历 73 q.push(t[tmp].rch); 74 75 } 76 }
这个版本也出现了一点问题,不知道哪里出错了,排错排的时间有点久,希望下次能加快发现错误的时间。
上周目标达成:因为假期出去玩的有点多,所以作业质量不是很好,但是改错的能力加强了,这点还是让人有感到成就感的,慢慢理解到了一些刚开始不懂得东西,比如自定义类型为什么要这样写之类的小问题。
本周目标:做到边打代码边写注释,而不是打完之后才写
继续认真复习,总结归纳
认真完成作业。