2017-2018-1 学习总结目录: 1 2 3 5 6 7 9 10 11 12
html
- 0. 教材学习内容总结
- 0.1 树
- 0.2 树的遍历
- 0.3 树的实现策略
- 0.4 二叉树的实现
- 0.5 决策树
- 1. 教材学习中的问题和解决过程
- 1.1 树的高度是否彻底等同于深度
- 1.2 课堂测试叶结点题目
- 2. 代码调试中的问题和解决过程
- 2.1 没法调用ArrayIterator类
栈、队列、链表都是线性数据结构,树是非线性结构(层次结构)。java
非线性结构:(一对多)
除根结点以外的每一个结点有且仅有一个直接前驱。
每一个结点能够有多个直接后继。
除根结点以外,其余结点都存在惟一一条从根结点到该结点的路径。node
树:结点 + 边(有限集合)
【注】结点数为0,称为空树。git
结点类型:根结点(惟一)、子结点、父结点、兄弟结点(同父)、叶节点(无子结点)、内部结点(非根叶结点)。算法
结点的度:结点的子树数。
树的度:结点的最大度数。(如:二叉树的度为2)
叶子(叶结点):度为0。
分支点:非终端结点。
数组
例如:上图中结点 K
L
F
G
M
I
J
的度为0,A
D
结点的度为3,B
E
结点的度为2,C
H
结点的度为1,结点 A
B
C
D
E
H
属于分支点。数据结构
结点的层次:根为第一层,以此类推。(从根到该结点的路径上的边数)
树的深度:结点的最大层次。
树的高度:从根到叶结点的最长路径的长度。
【注】深度不一样于高度,仍是以上图为例,该树的深度为4,高度为3。post
树的分类:n叉树(最大子结点数)、通常树(子结点无限制)、平衡树(子结点彼此不超出一层)、满树、彻底树。
学习
满树:全部叶结点在同一层,每一个非叶结点都正好有n个子结点。
彻底树:底层全部叶结点位于树的左侧,其他层结点全满。测试
例如:上图中a和b是 非满彻底树,只有c是 满彻底树。
m个元素的平衡的n叉树的高度为log\(_n\)m,例如:有n个结点的平衡二叉树的高度为log\(_2\)n。(计算时取整加一)
先序遍历:访问根后,从左到右遍历子树。
中序遍历:遍历左子树,而后访问根,以后从左到右遍历余下子树。(把树压扁)
后序遍历:从左到右遍历各子树,最后访问根。
层序遍历:从上到下,从左到右遍历结点。
public void preorder(ArrayIterator<T> iter){ iter.add(element); if(left != null) left.preorder(iter); if(right != null) right.preorder(iter); }
**中序遍历:**若二叉树为空,则空操做;不然
(1)中序遍历左子树;
(2)访问根结点;
(3)中序遍历右子树;
public void inorder(ArrayIterator<T> iter){ if(left != null) left.inorder(iter); iter.add(element); if(right != null) right.inorder(iter); }
**后序遍历:**若二叉树为空,则空操做;不然
(1)后序遍历左子树;
(2)后序遍历右子树;
(3)访问根结点;
public void postorder(ArrayIterator<T> iter){ if(left != null) left.postorder(iter); if(right != null) right.postorder(iter); iter.add(element); }
如上图所示,该树的不一样遍历方式依次遍历结点的顺序以下:
先序遍历:A
B
D
E
H
I
K
C
F
G
J
中序遍历:D
B
H
E
K
I
A
F
C
G
J
后序遍历:D
H
K
I
E
B
F
J
G
C
A
//树的根结点入队 //当队列不空时 { //结点出队列 //访问结点 //结点的左子结点入队 //结点的右子结点入队 }
public Iterator<T> levelorder() { LinkedQueue<BTNode<T>> queue = new LinkedQueue<>(); ArrayIterator<T> iter = new ArrayIterator<>(); if(root != null){ queue.enqueue(root); while(!queue.isEmpty()){ BTNode<T> current = queue.dequeue(); iter.add(current.getElement()); if(current.getLeft() != null) queue.enqueue(current.getLeft()); if(current.getRight() != null) queue.enqueue(current.getRight()); } } return iter; }
这三种遍历算法的访问路径是相同的,只是访问结点的时机不一样。
重要结论:中序 + 先序,或 中序 + 后序 均能惟一肯定一棵二叉树,但 先序 + 后序 却不必定能惟一肯定一棵二叉树。已知某棵二叉树,容易求得它的某种遍历序列。可是,反过来,若已知某种遍历序列,是否能够惟一肯定一棵二叉树呢?
使用数组表示树:存储在数组中位置为 n 的元素,元素的左子结点存储在(2n + 1)的位置,右子结点存储在(2 x(n+1))的位置。
链式结点:使用一个单独的类来定义树结点。
二叉树:树和子树的结点数最多有两个。
有序树:子树有左右之分。(左右不一样会形成二叉树不一样)
二叉树的 5 种不一样形态以下图:
二叉树的重要性质:
若二叉树的根结点位于第1层,则:
性质1:在二叉树的第 i 层最多有 \(2^{i-1}\) 个结点。(i ≥ 1)
性质2:深度为 k 的二叉树最多有 \(2^k\)-1 个结点。(k ≥ 1)
性质3:对任何一棵二叉树, 若是其叶结点个数为n\(_0\), 度为2的结点数为 n\(_2\), 则有:n\(_0\)=n\(_2\)+1。
特殊的二叉树:
满二叉树:每层 充满 结点,上文有解释。
深度为 k,层数为 i,根结点在第1层
结点总数\(2^k\)-1
每层结点数\(2^{i-1}\)
彻底二叉树:满二叉树去掉右下方的结点,上文有解释。
树中所含的 n 个结点和满二叉树中编号为 1 至 n 的结点一一对应。
彻底二叉树的性质:
性质1:具备n个结点的彻底二叉树的高度为[log\(_2\)n]+1
性质2:若是将一棵有 n 个结点的彻底二叉树自顶向下,同一层自左向右连续给结点编号1, 2, …, n,则对于任意结点 i (1 ≤ i ≤ n),有:
若i = 1, 则该 i 结点是树根,它无双亲;
若2i >n , 则编号为 i 的结点无左孩子, 不然它的左孩子是编号为 2*i 的结点 ;
若2i +1>n, 则编号为 i的结点无右孩子,不然其右孩子结点编号为 2*i+1;
public interface BinaryTree<T> extends Iterable<T> { // Returns the element stored in the root of the tree. public T getRootElement(); // Returns the left subtree of the root. public BinaryTree<T> getLeft(); // Returns the right subtree of the root. public BinaryTree<T> getRight(); // Returns true if the binary tree contains an element that matches the specified element. public boolean contains(T target); // Returns a reference to the element in the tree matching the specified target. public T find(T target); // Returns true if the binary tree contains no elements,and false otherwise. public boolean isEmpty(); // Returns the number of elements in this binary tree. public int size(); // Returns the string representation of the binary tree. public String toString(); // Returns a preorder traversal on the binary tree. public Iterator<T> preorder(); // Returns an inorder traversal on the binary tree. public Iterator<T> inorder(); // Returns a postorder traversal on the binary tree. public Iterator<T> postorder(); // Performs a level-order traversal on the binary tree. public Iterator<T> levelorder(); }
【问题1】:我看了书中第370页的定义:树的高度(height;或深度,depth)定义为树中从根到叶结点的最长路径的长度。图16.2中树的高度是3,由于从根到叶结点F(或G)的路径长度为3。我又看了老师的PPT,PPT中将A定义为第一层,这样就形成了该树的高度不等于深度,而书中的定义方式又说树的高度或深度,按照书中的意思理解,若是将A定义为第一层,则树的高度不等于深度,高度定义与路径长度有关,而路径长度为从根到该结点的路径上的边数。深度是指某结点的最大层次数。树的高度是否彻底等同于深度?
解决方案 :(思考并查找资料)
对于这种问题,我有个人见解:对于没有将根结点定义为第0层的树来讲,其高度不等于深度。查找到资料后验证个人猜测正确,一种解释为:
高度的定义为:从结点 x 向下到某个叶结点最长简单路径中边的条数。
【注意】对因而否是边的条数这个不清楚,待我后来查证,这个主要是因为其初值是1仍是0来肯定的,通常都是以1开始。
除此以外,我还得出了其余结论:
对于树中相同深度的每一个结点来讲,它们的高度不必定相同,这取决于每一个结点下面的叶结点的深度。
另外一种解释为:
引自考研大纲解析38页:树的深度是从根节点开始(其深度为1)自顶向下逐层累加的,而高度是从叶节点开始(其高度为1)自底向上逐层累加的。虽然树的深度和高度同样,可是具体到树的某个结点,其深度和高度是不同的。个人理解是:非根非叶结点的深度是从根节点数到它的,高度是从叶节点数到它的。
这两种解释异曲同工,树的高度只有在根结点被定义为第0层时其高度才等同于深度。
【问题2】:课堂测试中的第一题:
有100个结点的彻底二叉树,其高度是多少?叶结点数是多少?
第二问为何答案是50个叶结点?
解决方案 :(阅读课本)
我将课本和课件过了一遍,对于这样一个彻底二叉树,首先其高度为[log$_2$100] + 1 = 7,将根结点定义为第一层,则在第六层一共有32个结点,前六层一共有63个结点,因此第七层有100 - 63 - 1 = 37个叶结点,因此上一层左侧必定会有19个内部结点,因此第六层就会有 32 - 19 = 13 个叶结点,因此一共有 37 + 13 = 50个叶结点。以前答错是由于没有动手大体画一遍,只是空想公式,理论又不扎实,错误率就会很高。
【问题】:教材中的BTNode
类和LinkedBinaryTree
中的一些代码涉及到ArrayIterator
类,没法调用该类,在API,源码中查找也没有该类。
解决方案 :(思考)
对于这个问题,我认为在查找不到的状况下有两种方案解决此问题:
1、本身写这个类,实现其调用的方法;
2、修改或者替换这个类。
我采用了第二种方法,经过查找一些资料,我了解到ArrayIterator
类各不相同,确实是须要本身定义的,可是又以为有些麻烦(懈怠了),因此打算替换此类,看到以后调用的add()
方法,又看到原类的迭代对象是数组,因此我马上想到了ArrayList
类,正好该类又实现了Iterable
接口。个人尝试暂时没有问题,只是还缺乏一些测试来验证。
后来娄老师在上课时给出了自定义的ArrayIterator类,这个类继承了ArrayList类并实现了Iterator接口,加入后即可正常编译。
【错题1】When one type of object contains a link to another object of the same type, the object is sometimes called __________ .
A .circular
B .recursive
C .self-referential
D .a stack
E .a queue
错误缘由:书看得不细致,只凭本身的理解选了A。
加深理解:自指示关系的对象指的是同一类型的另外一个对象。自指示关系组成了链表的基础,所谓链表就是一个链式结构,一个对象指向下一个对象,创建了表中对象之间的线性关系。
【错题2】It is possible to implement a stack and a queue in such a way that all operations take a constant amount of time.
A .true
B .false
错误缘由:考虑到每一个操做的时间复杂度都是O(1),所以须要很短的时间,错选B。
加深理解:一个理想的堆栈或者一个理想的队列实现的全部操做都须要大量持续时间。
本周莫礼钟状态有些下滑,不过仍是抽出必定时间实现了使用链表实现队列的代码,掌握状况良好,除此以外还将课本上的十六章基础内容过了一遍,可是代码学习内容较少。本周也因为个人我的缘由致使与莫礼钟的学习交流较少。在团队任务方面,莫礼钟在例会上主动承担采访有经验的学长或者老师这一项任务,虽然完成质量有待提升,可是对于团队的积极性值得表扬。
本周个人状态良好,比上周的效率高一些,本周咱们学习了树结构,可是树的遍历方法仍然须要思考,包括上课时给出的一些重要结论和公式,这些都须要本身下去验证和熟悉。树结构在生活中的例子仍是不少的,并且还有些激发我对咱们团队游戏选取的兴趣。
本周的团队例会依然继续进行着,组建团队以后,我发现本身须要改进的地方还有不少,不只仅是技术方面,在管理方面、计划方面都须要仔细考虑,通知类的消息仍是落实到面对面交谈效果比较好,固然整体来讲咱们团队从一开始就很是出色,我以为咱们组只是按要求完成了老师的基础任务,并无每项都作到完美,可是有时也可以获得老师的表扬,这多是咱们学院学风的根源问题吧。下周,我依然会和组长一块儿带领团队继续前进。
【附1】教材及考试题中涉及到的英语:
Chinese | English | Chinese | English |
---|---|---|---|
边 | edge | 自指示 | self-referential |
兄弟结点 | sibling | 祖先 | ancestor |
内部结点 | internal node | 先序遍历 | preorder traversal |
子树 | subtree | 中序遍历 | inorder traversal |
后继 | descendant | 后序遍历 | postorder traversal |
度 | order | 层序遍历 | level-order traversal |
遍历 | traversal | 模拟 | simulation |
【附2】本周小组博客
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 234/234 | 1/28 | 14/14 | 了解算法效率、大O符号等理论内容 |
第二周 | 255/489 | 1/29 | 12/26 | 了解敏捷的团队、泛型的使用 |
第三周 | 436/925 | 2/31 | 10/36 | 了解一些查找和排序的算法 |
第四周 | 977/1902 | 3/34 | 10/46 | 掌握实现线性结构 |
第五周 | 800/2702 | 2/36 | 12/58 | 掌握实现栈集合 |
第六周 | 260/2962 | 1/37 | 8/64 | 掌握实现队列集合 |
第七周 | 843/3805 | 4/41 | 12/76 | 掌握实现树的基本结构 |
计划学习时间:14小时
实际学习时间:12小时
有效学习时间:5小时
改进状况:本周效率通常,主要感受在团队平常管理上花费的时间较多,不过本周代码进度较好,会继续保持。