20182328 2019-2020-1 《数据结构与面向对象程序设计》第九周学习总结
20182328 2019-2020-1 《数据结构与面向对象程序设计》第九周学习总结
教材学习内容总结
第16章
- 树的概念:树是一个非线性集合,其中元素为层次结构
- 树的分类
1、根据树中的最大结点个数来分
2、按树是否平衡来分 - 树的遍历(4种方法)
1、先序遍历:先访问根,再访问左右子树。
public void preOrderTraverse2(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
TreeNode node = root;
while (node != null || !stack.empty()) {
if (node != null) {
System.out.print(node.val + "->");
stack.push(node);
node = node.left;
} else {
TreeNode tem = stack.pop();
node = tem.right;
}
}
}
2、中序遍历:先遍历左子树,再访问根节点,再访问右子树。
public void inOrderTraverse(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
TreeNode node = root;
while (node != null || !stack.isEmpty()) {
if (node != null) {
stack.push(node);
node = node.left;
} else {
TreeNode tem = stack.pop();
System.out.print(tem.val + "->");
node = tem.right;
}
}
}
3、后序遍历:先便利左子树,再遍历右子树,最后遍历根节点。
public void postOrderTraverse(TreeNode root) {
TreeNode cur, pre = null;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.empty()) {
cur = stack.peek();
if ((cur.left == null && cur.right == null) || (pre != null && (pre == cur.left || pre == cur.right))) {
System.out.print(cur.val + "->");
stack.pop();
pre = cur;
} else {
if (cur.right != null)
stack.push(cur.right);
if (cur.left != null)
stack.push(cur.left);
}
}
}
4、层序遍历:从树的顶层到底层,从左到右,访问树中每层的结点。
public void levelOrderTraverse(TreeNode root) {
if (root == null) {
return;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.add(root);
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
System.out.print(node.val + "->");
if (node.left != null) {
queue.add(node.left);
}
if (node.right != null) {
queue.add(node.right);
}
}
}
- 如何使用一个数组来表示树,并将元素连续储存到数组中
- 二叉树的实现
介绍:
二叉树是一个递归的数据结构,每个节点最多有两个子节点。
通常二叉树是二分查找树,每个节点它的值大于或者等于在它左子树节点上的值,小于或者等于在它右子树节点上的值
二叉树的存储结构:
1、顺序存储:采用数组,顺序存储适配于完全二叉树,对于非完全二叉树并不合适,主要体现在空间上的浪费,所以我们需要用到另一种存储方式——链式存储。
2、链式存储:数据data用键值对的形式表示
建立二叉树:
为了实现二叉树,我们使用一个Node类来表示节点,节点存储元素的值,还有对子节点的引用。
package com.java.node.BinaryTree;
public class Node {
int data;
Node left;
Node right;
public Node(int data) {
this.data = data;
this.left = null;
this.right = null;
}
}
然后添加树的root节点
package com.java.node.BinaryTree;
public class BinaryTree {
Node root;
}
- 二叉查找树
基本概念:二叉查找树是一种特殊的二叉树,要求左子树的全部节点小于父亲节点,右子树的全部节点大于父亲节点,同时,左子树和右子树也为二叉查找树,中序遍历一个二叉查找树,会得到一个有序的元素集合。
性质:
1、若它的左子树不为空,则左子树上的所有节点的值都小于它的根节点的值;
2、若它的右子树不为空,则右子树上所有节点的值都大于它的根节点的值;
3、其他的左右子树也分别为二叉查找树;
4、二叉查找树是动态查找表,在查找的过程中可见添加和删除相应的元素。
基本操作 - 1、查找
实现思路:查找某个节点,相当于二分查找,如果小于当前节点,则走左边,如果大于当前节点,则走右边。当最后叶子节点还没有找到,则没有找到。
代码:
public Node findNode(int key){
Node current = root;
while(current.index != key){
if(key < current.index){
current = current.leftNode;
}else{
current = current.rightNode;
}
if(current == null){
return null;
}
}
return current;
}
- 2、插入
实现思路:递归地去遍历一颗树,如果大于节点就遍历节点的右子树,如果小于节点就遍历节点的左子树,当节点为空时插入。
代码:
public static void insert(Tree tree,int value)
{
if(tree.getValue() == null)
{
tree.setValue(value);
}
else if(tree.getValue() < value)
{
if(tree.getrChild()!=null)
{
insert(tree.getrChild(),value);
}
else {
tree.setrChild(new Tree());
insert(tree.getrChild(),value);
}
}
else if(tree.getValue() > value)
{
if(tree.getlChild()!=null)
{
insert(tree.getlChild(),value);
}
else {
tree.setlChild(new Tree());
insert(tree.getlChild(),value);
}
}
}
- 3、删除
实现思路:
(1)、删除节点没有子节点,那么将父节点的左节点或者是右节点设置为空
(2)、删除节点只有一个子节点,删除该节点后,该节点的子节点变为父节点的子节点,如果删除节点时父节点的左节点,那么父节点的左节点指向该节点的子节点,反之则右节点指向删除节点的子节点。
(3)、删除节点有两个字节点,删除了该节点后,则需要选择一个后继节点,并且还不破坏该二叉树的特性(左节点要小于右节点),一般是从删除节点的右节点中找到一个后继节点,而这个节点是右子树的最小值。
代码:
public static void delete(Tree tree,int value)
{
Tree parent = null;
Tree searchTree = tree;
while(searchTree != null)
{
if(searchTree.getValue()==value)
{
break;
}
else if(searchTree.getValue() > value)
{
parent = searchTree;
searchTree = searchTree.getlChild();
}
else if(searchTree.getValue() < value)
{
parent = searchTree;
searchTree = searchTree.getrChild();
}
}
boolean parentLeftFlag = false;
boolean hasParent = true;
boolean leftFlag = false;
boolean rightFlag = false;
if(parent == null)
{
hasParent = false;
}
else if(parent.getrChild() == searchTree)
{
parentLeftFlag = false;
}
else{
parentLeftFlag = true;
}
if(searchTree == null)
{
return;
}
if(searchTree.getlChild() != null){
leftFlag = true;
}
if(searchTree.getrChild() != null){
rightFlag = true;
}
if(!leftFlag && !rightFlag)
{
if(hasParent)
{
if(parentLeftFlag)
{
parent.setlChild(null);
}
else{
parent.setrChild(null);
}
}
else{
searchTree.setValue(null);
}
}
else if(!leftFlag || !rightFlag)
{
if(hasParent)
{
if(parentLeftFlag)
{
if(leftFlag)
{
parent.setlChild(searchTree.getlChild());
}
else {
parent.setlChild(searchTree.getrChild());
}
}
else {
if(leftFlag)
{
parent.setrChild(searchTree.getlChild());
}
else {
parent.setrChild(searchTree.getrChild());
}
}
}
else
{
if(leftFlag){
searchTree.setValue(searchTree.getlChild().getValue());
searchTree.setrChild(searchTree.getlChild().getrChild());
searchTree.setlChild(searchTree.getlChild().getlChild());
}
else
{
searchTree.setValue(searchTree.getrChild().getValue());
searchTree.setlChild(searchTree.getrChild().getlChild());
searchTree.setrChild(searchTree.getrChild().getrChild());
}
}
}
else if(leftFlag && rightFlag){
Tree minTree = searchTree.getrChild();
while (minTree.getlChild() != null)
{
minTree = minTree.getlChild();
}
Integer minTreeValue = minTree.getValue();
delete(searchTree,minTreeValue);
searchTree.setValue(minTreeValue);
}
}
教材学习中的问题和解决过程
- 问题1:用计算链实现二叉树的优势和不足分别是什么?
- 问题1解决方案:计算链策略不需要保存父节点和子节点之间的链,因为关系由数组中的位置来决定。但是这个策略对不平衡树或不完全树,可能会浪费树的储存空间。
- 问题2:二叉树和二叉查找树有什么不同
- 问题2解决方案:二叉查找树是添加了次序特征的一颗二叉树,每个结点小于结点并大于等于它的右子结点,普通·的二叉树在其元素之间没有限制。
代码调试中的问题和解决过程
- 问题1:问题1:不知道如何实现linkedBinaryTree中的toString方法。
- 问题1解决方案:用迭代器接解决。
- 问题2:在进行决策树的实验中中,出现了找不到行的问题。
- 问题2解决方案:scanner的引用过多会导致系统紊乱,删掉其中的一个
代码托管
上周考试错题总结
- If a binary search tree is not __________, it may be less efficient than a linear structure.
A .complete
B .empty
C .balanced
D .None of the above
正确答案: C 我的答案: B - The balance restriction on a red/black tree is somewhat less strict than that for AVL trees. However, in both cases, the find operation is order ______.
A .n
B .log n
C .n log n
D .None of the above
正确答案: B 你的答案: C - The balance restriction on a red/black tree is somewhat less strict than that for AVL trees. However, in both cases, the find operation is order n.
A .True
B .Flase
正确答案: B 你的答案: A
结对及互评
评分标准
- 基于评分标准,我给本博客打分:15分。得分情况如下:
- 正确使用Markdown语法(加1分):
- 模板中的要素齐全(加1分)
- 教材学习中的问题和解决过程,加2分
- 代码调试中的问题和解决过程,加2分
- 本周有效代码超过300分行的(加2分)
- 其他加分:
- 扣分:0分
点评模板:
-
博客中值得学习的或问题:
- 内容详实且精简
- 问题充分且已解决
-
代码中值得学习的或问题:
- 正确且简练
- 方法多样很值得学习
点评过的同学博客和代码
- 本周结对学习情况
其他(感悟、思考等,可选)
1、这周学的内容又开始逐渐变难了,有点跟不上,但是多抽出点空闲时间还是能够学到更多东西的,我会尽量抽出更多的时间去敲代码。
2、多敲一敲课本上的代码,累计代码量,打好基础。
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 200/200 | 2/2 | 20/20 | |
第二周 | 300/500 | 2/4 | 18/38 | |
第三周 | 500/1000 | 3/7 | 22/60 | |
第四周 | 300/1300 | 2/9 | 30/90 |
尝试一下记录「计划学习时间」和「实际学习时间」,到期末看看能不能改进自己的计划能力。这个工作学习中很重要,也很有用。
耗时估计的公式:Y=X+X/N ,Y=X-X/N,训练次数多了,X、Y就接近了。
-
计划学习时间:XX小时
-
实际学习时间:XX小时
-
改进情况:
(有空多看看现代软件工程 课件
软件工程师能力自我评价表)