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分。得分情况如下:
  1. 正确使用Markdown语法(加1分):
  2. 模板中的要素齐全(加1分)
  3. 教材学习中的问题和解决过程,加2分
  4. 代码调试中的问题和解决过程,加2分
  5. 本周有效代码超过300分行的(加2分)
  6. 其他加分:
  7. 扣分: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小时

  • 改进情况:

(有空多看看现代软件工程 课件
软件工程师能力自我评价表
)

参考资料

posted @ 2019-11-19 20:37  20182328张景昊  阅读(200)  评论(1编辑  收藏  举报