20182322 2019-2020-1 《数据结构与面向对象程序设计》第10周学习总结

教材学习内容总结

树的定义是,除根结点之外,树的每个结点都恰好有一个父结点。
而如果违背了这一个前提,即允许树的每个结点连通多个其它结点,不再有父亲、孩子之说,即得到孩子的概念

一、无向图

  • 图与树类似,也由结点和这些结点之间的连接构成(这些结点就是图的顶点,而结点之间的连接就是图的边)
  • 无向图是一种边为无序结点对的图
  • 如果图中的两个顶点之间有一条连通边,则称这两个顶点是邻接的(也互称邻居)
  • 连通一个顶点及其自身的边称为自循环或环
  • 如果无向图拥有最大数目的连通顶点的边,则认为这个无向图是完全的
  • 对有n个顶点的无向图,要使该图为完全的,要求有n(n-1)/2条边(这里假设其中没有边是自循环的)
  • 路径是图中的一系列边,每条边连通两个顶点(无向图中的路径是双向的)
  • 如果无向图中的任意两个顶点之间都存在一条路径,则认为这个无向图是连通的
  • 环路是一种首顶点和末顶点相同且没有重边的路径
  • 没有环路的图称为无环的
  • 无向树是一种连通的无环无向图,其中一个元素被指定为树根

二、有向图

  • 有向图(双向图),它是一种边为有序顶点对的图
  • 有向图的路径是图中连通两个顶点的有向边序列(有向图中的路径不是双向的)
  • 如果有向图中没有环路,且有一条从A到B的边,则可以把顶点A安排在顶点B之前。这种排列得到的顶点次序称为拓扑序

三、网络(加权图)

  • 网络:一种每条边都带有权重的或代价的图
  • 根据需要,网络可以是无向的,也可以是有向的
  • 对于网络,可以用一个三元组来表示每条边(包括起始顶点、终止顶点、权重)
    image
    image

四、常用的图算法

  • breadth-firsttraversal:宽度优先遍历 图的一种遍历,类似于树的层次遍历。
  • depth-firsttraversal:深度优先遍历 图的一种遍历,类似于树的前序遍历。
  • 图的深度优先遍历与广度优先遍历的唯一不同是,它使用的是栈而不是队列来管理遍历。
  • image
  • 不论哪个为起始顶点,当且仅当广度优先遍历中的顶点数目等于图中的顶点数目时,该图才是连通的。

-无向连通图 image

  • image
  • spanningtree:生成树 是一棵含有图中所有顶点和部分边(但可能不是所有边)的树。
  • minimumspanningtree:最小生成树 是这样一棵生成树,其边的权重总和小于或等于同一个图中其他任何一棵生成树的权重总和。
  • image

五、图的实现策略

  • 图的方法和树中的很类似。会有size、isEmpty、toString、find、最短路径的操作、判定两顶点间是否邻接的操作、构造最小生成树的操作、测试连通性的操作、两种遍历方法的操作
  • 对图结点来说,由于每个结点可以有多达n-1条边与其他结点相连,因此最好用一种类似于链表的动态结点来存储每个结点带有的边,这种链表称为邻接列表
  • 邻接矩阵:一种二维数组,其中每个单元都表示了图中两个顶点的交接情况,对于无向图,数组中的每个单元是一个布尔值,对于加权图,在数组中还存储了权重
  • 对于无向图来说,它是双方向的,所以我们在做邻接矩阵的时候,其实只需要矩阵对角线的一侧即可
  • 对于有向图来说,就和无向图不同,就根据箭头之间的邻接来确定布尔值。
  • image

教材学习中的问题和解决过程

  • 问题1:在学习教材的时候,最小生成树的方法中有这样一行代码“resultGraph[][] = Double.Positive_INFINITY”,不是很理解这里的POSITIVE_INFINITY代表什么意思。
  • 问题1解决方案:我深入思考这样一个问题,在进行浮点数运算的时候,有时我们会遇到除数为0的情况,那我们该如何解决呢?所以引入了无限这个概念,POSITIVE_INFINITY正是可以用来代表无限。示例如下
double i = Double.POSITIVE_INFINITY;   // i表示为无限大

public static final double POSITIVE_INFINITY = 1.0 / 0.0;
  • 问题2:书上说测试连通性,通过比较广度优先遍历中的顶点数目和图中的顶点数目是否相等来判断。也就是说任意一个顶点都必须满足这个条件。那么,我们为什么不只要判断出有广度优先遍历的顶点数目和图中的顶点数目不相等的时候就不连通呢,这样可以有效减少遍历次数,优化算法的效率。

  • 问题2解决方案:

    • 虽然,图示中给的是测试无向图的连通性,但是,我们需要考虑有向图。在有向图中,路径是不可逆的,也就是说,顶点存在有可能正向出发遍历所有的顶点,而反向却不可以。 这时,为了保证任意顶点广度优先遍历的顶点数目和图中的顶点数目相等,我们需要从所有顶点遍历一次。
    • 但是对于无向图来说,我认为是可行的。但是算法的复杂度并没有减少,只是提高了效率。
  • 问题3:书上关于无向图的邻接矩阵实现中是矩阵中的元素如果为一则是连通的,并且是对称的,那么对于加权图来说如何实现?

  • 问题3解决方案:其实这个问题非常简单,只是自己的脑子没扭过来,直接把那个1变为需要加上的权重就实现了加权图。

代码调试中的问题和解决过程

  • 问题1:在实现书上的Graph类补全时遇到一些困难。
  • 问题1解决方案:参考了一些同学的代码,并且对我自己的代码进行了一些优化,例如isEmpty方法,原本的代码如下:
public boolean isEmpty()
    {
        if (numVertices == 0)
        {
            return true;
        }
        else {
            return false;
        }
    }
  • 参考同学代码如下
public boolean isEmpty()
    {
    return (numVertices == 0)
    }

自己想了想发现这样的确会简单很多。这告诉我们应该多多想想算法的优化。

  • 问题2:对广度优先遍历代码的理解
  • 问题2解决方案:见注释
private Iterator<T> iteratorBFS(int startIndex) {
    Integer x;
    QueueADT<Integer> traversalQueue = new LinkedQueue<Integer>();
    UnorderedListADT<T> resultList = new ArrayUnorderedList<T>();
    //索引无效,返回空
    if (!indexIsValid(startIndex))
        return resultList.iterator();
    boolean[] visited = new boolean[maxCount];
    //把所有顶点设为false,白色
    for (int i = 0; i < maxCount; i++)
        visited[i] = false;
    //进入队列的为true,即访问过的,灰色
    traversalQueue.enqueue(startIndex);
    visited[startIndex] = true;
    while (!traversalQueue.isEmpty()) {
        //出队列涂黑存入resultList中
        x = traversalQueue.dequeue();
        resultList.addToRear((T) nodelist.get(x).getElement());
        //如果进入resultList的顶点还有相邻的未访问过的顶点,将其涂灰入队
        for (int i = 0; i < maxCount; i++) {
            if (hasEdge(x, i) && !visited[i]) {
                traversalQueue.enqueue(i);
                visited[i] = true;
                Int++;
            }
        }
    }
    return new GraphIterator(resultList.iterator());
    }

代码托管

  • 由于一些意外把IDEA卸掉了,所以代码数清零

上周考试错题总结

  • 上周没考试

结对及互评

评分标准

  1. 正确使用Markdown语法(加1分):

    • 不使用Markdown不加分
    • 有语法错误的不加分(链接打不开,表格不对,列表不正确...)
    • 排版混乱的不加分
  2. 模板中的要素齐全(加1分)

    • 缺少“教材学习中的问题和解决过程”的不加分
    • 缺少“代码调试中的问题和解决过程”的不加分
    • 代码托管不能打开的不加分
    • 缺少“结对及互评”的不能打开的不加分
    • 缺少“上周考试错题总结”的不能加分
    • 缺少“进度条”的不能加分
    • 缺少“参考资料”的不能加分
  3. 教材学习中的问题和解决过程, 一个问题加1分

  4. 代码调试中的问题和解决过程, 一个问题加1分

  5. 本周有效代码超过300分行的(加2分)

    • 一周提交次数少于20次的不加分
  6. 其他加分:

    • 周五前发博客的加1分
    • 感想,体会不假大空的加1分
    • 排版精美的加一分
    • 进度条中记录学习时间与改进情况的加1分
    • 有动手写新代码的加1分
    • 课后选择题有验证的加1分
    • 代码Commit Message规范的加1分
    • 错题学习深入的加1分
    • 点评认真,能指出博客和代码中的问题的加1分
    • 结对学习情况真实可信的加1分
  7. 扣分:

    • 有抄袭的扣至0分
    • 代码作弊的扣至0分
    • 迟交作业的扣至0分

点评模板:

  • 博客中值得学习的或问题:

    • 排版工整
    • 对问题都深入研究
  • 代码中值得学习的或问题:

    • 代码有自己的理解
    • 代码排列不大美观
  • 基于评分标准,我给本博客打分:9分。得分情况如下:

  • 正确使用Markdown语法+1.

  • 教材学习中的问题和解决过程+2.代码调试中的问题和解决过程+2.

  • 感想,体会不假大空+1.

  • 错题学习深入+1.

  • 点评认真.课后题有验证+1.

  • 进度条有记录+1.

点评过的同学博客和代码

其他(感悟、思考等,可选)

  • 关于图的概念有逻辑性,容易理解,但是问题还是在代码理解上,我觉得Java学习不能停留在知识表面,要深入理解代码,并学会构造才是最终目的。
  • 本章的难度不仅难在算法的理解上,还难在代码的实现上,光是学习算法就花费了不少时间,关键代码的理解也不容易。但这周学下来总体上说收获还是挺大的,这周的学习状态也还算可以,希望自己能够继续保持这样的状态,继续进步吧!

学习进度条

代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
目标 10000行 30篇 400小时
第一周 59/200 2/2 20/20
第三周 292/331 2/4 20/40
第四周 677/969 2/6 20/60
第五周 661/1265 2/8 20/80
第六周 1299 /2554 2/10 20/100
第七周 1500/4054 2/12 20/120
第九周 6049/10103 2/14 20/140
第十周 1049/11152 2/16 20/160
  • 计划学习时间:20小时

  • 实际学习时间:20小时

  • 改进情况:越到后面,学习越紧张,顶住!!!

参考资料

posted @ 2019-11-27 21:09  20182322王美皓  阅读(266)  评论(0编辑  收藏  举报