20192328牛梓萌 2019-2020-2《数据结构与面向对象程序设计》课程总结

20192328牛梓萌 2019-2020-2《数据结构与面向对象程序设计》课程总结

课程内容总结

第1章 绪论

了解java程序设计语言的基本情况和本书的专业术语的介绍。
掌握Linux、vim基本命令
了解并学习什么是markdown格式
简单编程、编译、调试并实现代码托管

第2章 数据和表达式

  • 字符串
  • 变量
  • 赋值语句
    不能将一个类型的值赋给与之不匹配的另一个类型的变量。
  • 基本数据类型
    Java一共有8种基本数据类型:boolean、byte、short、int、long、float、double、char
    这8种基本数据类型可以分为
    逻辑类型:boolean
    常量:true、false
    整数类型:byte、short、int、long
  • 表达式
    表达式由运算符及操作数组成,用来执行一个计算。
  • 数据转换
    Java中数据的基本类型(不包括逻辑类型)按精度从低到高:
    byte short char int long float double
    当把精度低的赋值给精度高的(从左到右)变量时,系统自动完成转换:例如:float x = 100;
    当把精度高的赋值给精度低的(从右到左)变量时,必须显示加强制类型转换,例如: int x=(int)3.14;
    把一个int类型的常量赋值给一个byte或者一个short类型变量时,如果超出byte或者short的范围必须加强制类型转换,例如
    byte a = (byte)128;
  • 读输入数据
  • 输入数据
    可以使用Scanner类创建一个对象:
    Scanner reader = new Scanner(System.in);
  • 输出数据
    System.out.println()和System.out.print()都可输出数据,区别是前者换行、后者不换行。

第3章 使用类和对象

  • 创建对象
    new运算符返回新的创建对象的应用。

  • String类


  • Random类:

  • math类

Math类的所有方法都是静态的,即通过类名来调动它们
Math类有一个Random方法,返回0.0~0.1的浮点随机数。eg:static double random()。
根号下如果是负的,java将其表示为NAN。

  • 格式化输出
    NumberFormat类中getPercentInstance是以百分比格式输出,getCurrencyInstance方法是以货币格式输出。DecimalFormat类是以十进制格式输出。声明是import java. text.DecimalFormat。
  • 枚举类型
    枚举类型是类型安全的,可以保证不会使用非法的值。
  • 包装类
    自动包装提供基本数据类型与对应的包装类之间的自动转换

第4章 条件和循环

  • 布尔表达式
    相等性运算符:“==”,“!=”
    数据比较
    普通数据比较
    浮点数比较:Math.abs(r1-r2) < 0.0001,接近即认为相等
    字符比较:unicode值比较
    字符串比较:String类提供的方法compareTo(P76)- 0 +(返回非布尔值)
    还有一个equals,string1.equals(string2) true/false
    对象比较:要implements Comparable接口
    public class Student{
    String name;
    Double score;
    …………//省略了方法
    }
    关系运算符:“>”、“<”、“>=”、“<=”
    优先级:以上两个运算符的优先级<算术运算符
    1+2 == 3+4
    逻辑运算符:“!”、“&&”、“||”(!的优先级最高)
    a>b 1 0 c >d 0 1
    ! 0 1 1 0
    a>b && c >d

  • if语句
    它由三部分组成: 关键字本身, 用于判断结果真假的条件表达式, 以及当表达式为真或者非零时执行的代码块

  • 数据比较
    浮点数的比较
    字符比较
    对象比较

  • switch语句
    当变量的值与 case 语句的值相等时,那么 case 语句之后的语句开始执行,直到 break 语句出现才会跳出 switch 语句。
    当遇到 break 语句时,switch 语句终止。程序跳转到 switch 语句后面的语句执行。
    case 语句不必须要包含 break 语句。如果没有 break 语句出现,程序会继续执行下一条 case 语句,直到出现 break 语句。

  • while语句

循环语句允许重复执行一个语句或一组语句。

while是最基本的循环,它的结构为:

while( 布尔表达式 ) {
//循环内容
}
只要布尔表达式为 true,循环体会一直执行下去。

  • 迭代器

用 for 循环访问迭代器和访问序列的方法差不多. 唯一的区别就是 for 语句会为你做一些额外的事情
迭代器并不代表循环条目的集合
迭代器对象有一个 next() 方法, 调用后返回下一个条目.
所有条目迭代完后, 迭代器引发一个 StopIteration 异常告诉程序循环结束. for 语句在内部调用 next() 并捕获异常.

  • do 语句

do…while 循环和 while 循环相似,不同的是,do…while 循环至少会执行一次。

do...while 循环的结构为:

do {
//代码语句
}while(布尔表达式);

  • for 语句

for 循环执行的次数是在执行前就确定的。语法格式如下:

for(初始化; 布尔表达式; 更新) {
//代码语句
}
关于 for 循环有以下几点说明:

最先执行初始化步骤。可以声明一种类型,但可初始化一个或多个循环控制变量,也可以是空语句。
然后,检测布尔表达式的值。如果为 true,循环体被执行。如果为false,循环终止,开始执行循环体后面的语句。
执行一次循环后,更新循环控制变量。
再次检测布尔表达式。循环执行上面的过程。

第5章 编写类

  • 再谈类和对象

对象:对象是类的一个实例,有状态和行为。
类:类是一个模板,它描述一类对象的行为和状态。
类是对象的蓝图。

  • 类的剖析
    实例数据
    UML类图
    UML类图有助于呈现程序中类的内容和类之间的关系
    了解UML这种统一建模语言,学习类名、属性(数据)、操作(方法)之间的关系。
  • 封装
    不允许对象的代码直接访问变量,只能调用
    可见性修饰符控制类中成员的访问权限。public,private和protected
    访问方法:getX;设置方法:setX;客户可以通过它管理数据
    (介绍了可见性修饰符中的public和private。在UML中+表示public可见性,-表示private可见性)
  • 方法的剖析
    return语句
    参数
    局部数据
  • 静态类成员
    静态变量(由类中所有实例所共享)
    静态方法(可以通过类名来调用)
  • 类关系

依赖

聚合

this引用

  • 方法设计
    方法的分解(对象提供的一个复杂的服务可以分解为几个私有支撑方法)
    方法参数

  • 方法重载

让多个方法使用相同的方法名但有不同的参数列表
当调用方法时,控制流将转用定义方法的代码
重载方法的各个版本由参数个数、类型及次序来区分
eg:参数的类型、个数等不同

  • 测试
    审核:用来评价设计或代码的一项技术
    缺陷测试:可以发现错误,进行黑盒测试
    单元测试:每个测试创建一个测试用例
    集成测试:作为一个整体进行测试
    系统测试:观察需求
    测试驱动开发:先写测试用例,再进行源代码

  • 调试
    就是定位并修正程序中的运行时错误及逻辑错误的行为

第6章 图形用户界面

GUI 组件 布局

第7章 数组

和c语言类似

第8章 继承

  • 创建子类
    继承是从已有类派生一个新类的过程
    继承的目的之一是复用已有的软件
    继承在父类与子类之间建立了is-a的关系
    类的继承格式
    class 父类{};
    class 子类 extends 父类{};
    interface 父类{};
    class 子类 implements 父类{};
    super和this
    super:可以通过super来实现对父类的访问,用来引用当前对象的父类
    this:指向自己的引用
    构造函数
    (1)子类不能继承父类的构造函数,但是父类的构造函数带有参数的,则必须在子类的构造函数中显式地通过super关键字调用父类的构造函数并配以适当的参数列表。
    super(name,id)
    (2)如果父类有无参构造函数,则在子类的构造器中用super调用父类构造函数不是必须的,如果没有使用super关键字,系统会自动调用父类的无参构造器。
    super()可有可无

  • 方法的重写

方法重写:子类定义的方法与父类定义的方法有相同名字和相同签名
重写方法:即子类和父类里面有相同的方法和签名时,子类方法可以重写父类方法,子类方法优先。调用方法的对象决定决定了哪一个版本的方法将被实际执行。

  • 类层次

父类派生子类,子类可以继续派生
公共特性应该放到类层次尽可能高的位置上
object类
object类在java标准类库java.lang包中定义
java中所有的类都派生自object类
java中每个类都继承了toString和equals方法
如果一个类定义时没有显示的指名其父类,那么此类继承自object类。因此,object类是类层次结构中的根类。
抽象类
在类层次结构中,高层很多设计为抽象类。
接口类:常量+抽象方法
抽象类:常量/变量+抽象/非抽象方法(Notes:抽象类可以不包含抽象方法)

和接口类一样,抽象类不能被实例化!(包含未实现的方法)
和接口类不同,抽象类中的方法必须使用abstract修饰。(接口中所有方法都是抽象的,可以省略abstract,也可以使用!)
接口的层次结构
类似于类的层次结构,不同的地方:
可以implements多个接口(多继承);
implements接口时,必须实现所有父接口中的方法

  • 可见性
    私有成员也被子类继承,但不能通过名字直接引用。不过可以间接引用他们。
  • 设计继承
    每次派生操作都应是一个is-a关系。子类应该是更具体的父类对象
    设计类层次是为了复用,或是将来可以复用
    在问题域中标出类和对象时,找出他们的共性。共性处于越高层次,越能保持一致性,进行维护。
    适当地重写方法来满足子类性能
    按需给子类添加新的变量,但不要隐藏继承的任何变量
    允许每个类管理它自己的数据。所以使用super引用来调用构造方法,可以用它调用被重写的方法
    设计类层次来满足应用需求,需要注意将来如何使用
    即使目前并不使用,也要适当地在子类重写toString和equals这类的一般方法,以便将来派生的类不会出现问题
    使用抽象类来为类层次中的具体类指定一个公共类接口
    谨慎使用可见性修饰符,在派生类中提供不违背封装原则访问即可。

第9章 多态

  • 多态引用
  • 多态与继承
  • 多态与接口
  • 使用多态实现排序与搜索算法

    搜索:线性、二分

第10章 异常

  • 异常
    程序中出现的问题或者非正常情况
  • 异常处理
    错误和异常代表不常见的或不正确处理的对象
    三张方式:
    不处理异常
    在异常发生的地方处理
    在程序的其他地方处理异常
    try-catch语句
    接在try块后的catch子句定义如何处理一种具体异常,一个try可以对多个touch
    finally无论如何都要执行
  • 异常传递
    如果下级没有处理异常,将会把异常传递给上级调用方法
  • 异常的结构层次
  • IO
    IO流
    Java IO文件操作(文件创建和读写)

第11章 递归

  • 递归思想
  • 递归程序设计
  • 使用递归

第12章 算法分析

  • 算法效率
  • 增长函数和大O符号
  • 比较增长函数

第13章 查找与排序

  • 查找

    线性查找:依次将每个值进行查找
    Comparable 接口允许多态实现算法,而不是只应用于特定的类
while (result == null&&index<data.length){
    if (data[index].compareTo(target)==0)
    result=data[index];
    index++;
}

二分查找

    Comparable result = null;
    int first = 0 ,last = data.length-1
while( result ==null && first <=last){
    mid =(first + last)/2;
    if(data[mid].compareTo(target)==0)
    result=data[mid];
    else
    if(data[mid].compareTo(target)>0)
    last = mid-1;
    else
    first = mid+1;
}

-排序

选择排序

void SelectSort(int a[],int n) //选择排序
{
    int mix,temp;
    for(int i=0;i<n-1;i++) 
    {
        mix=i; 
        for(int j=i+1;j<n;j++) 
            if(a[j]<a[mix])
                mix=j;
       
        if(i!=mix)
        {
            temp=a[i];
            a[i]=a[mix];
            a[mix]=temp;
        }
    }
}

插入排序

public Integer[] sort(Integer[] a) {
    
        print("init",a);
        Integer temp = 0;
        for(int i=1;i<a.length;i++) {
           
            for(int j=i;j>0 && a[j] < a[j-1];j--) {
                temp = a[j];
                a[j] = a[j-1];
                a[j-1] = temp;
            }
            print(i +"",a);
        }
        print("result",a);
        return a;
    }

冒泡排序

public void bubbleSort(Integer[] arr, int n) {
        if (n <= 1) return; 
        for (int i = 0; i < n; ++i) {
           
            boolean flag = false;
            for (int j = 0; j < n - i - 1; ++j) {      
                if (arr[j] > arr[j + 1]) {      
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                    flag = true;
                }
            }
            if (!flag) break;
        }

快速排序

   public static void quickSort(int[] arr,int low,int high){
        int i,j,temp,t;
        if(low>high){
            return;        }
        i=low;
        j=high;
       
        temp = arr[low];
        while (i<j) {
          
            while (temp<=arr[j]&&i<j) {
                j--;
            }
           
            while (temp>=arr[i]&&i<j) {
                i++;
            }
         
            if (i<j) {
                t = arr[j];
                arr[j] = arr[i];
                arr[i] = t;            }
        }
    
         arr[low] = arr[i];
         arr[i] = temp;
       
        quickSort(arr, low, j-1);
    
        quickSort(arr, j+1, high);
    }

归并排序

public static int[] sort(int[] a,int low,int high){
        int mid = (low+high)/2;
        if(low<high){
            sort(a,low,mid);
            sort(a,mid+1,high);
            merge(a,low,mid,high);
        }
        return a;
    }
     
    public static void merge(int[] a, int low, int mid, int high) {
        int[] temp = new int[high-low+1];
        int i= low;
        int j = mid+1;
        int k=0;
      
        while(i<=mid && j<=high){
            if(a[i]<a[j]){
                temp[k++] = a[i++];
            }else{
                temp[k++] = a[j++];
            }
        }
  
        while(i<=mid){
            temp[k++] = a[i++];
        }
        while(j<=high){
            temp[k++] = a[j++];
        }
        for(int x=0;x<temp.length;x++){
            a[x+low] = temp[x];
        }
    }

第14章 栈

  • 链表实现栈

  • 尾插法

Student temp = Head;
while(temp.next!=null){
temp=temp.next}
temp.next=node;
return head;

用一个临时指针(不能影响头指针,头指针移动则垃圾回收)等于头指针temp=temp。next 若为null,找到了链表结尾,则指向新插入的对象

  • 头插法:新对象指向首个元素,head指针赋给新对象,则新链表完成
node.next=Head;
Head =node;
return Head;
  • 删除
temp.next=temp.next.next
  • 栈的应用
    数值转换

表达式求值

第15章 队列

  • 队列:只能在队头删除,队尾插入。先进先出(队列等连续存储结构可以随机存取,链表不可以,必须从第一个开始找)
  • 队列的基本操作

方法:enqueue入队
dequeue出队
first=peek看第一个元素
isEmpty是否为空
size多少元素

  • 定义结点
    LinerNode
    LinerNode front //队头指针
    LinerNoderear // 队尾指针
    int count//元素个数

  • 循环队列

  • 线性表
    具有相同特性数据元素的有限序列
    栈队列是特殊的线性表
    出队入队操作:
    为空时rear front都在1(不是指针),为空判定条件:(rearfront)也有可能队满!
    (1) 少用一个空间,判断(rear+1)%M=front
    (2) size
    (3)看上一步操作,确定是front导致的还是rear导致的)
    入队rear+1,q[rear++]=x;
    出队front+1,e=q[front++];
    假溢出:0 1 2 3 4 5 浪费空间
    (出队元素)
    解决:
    (1)依次固定
    (2) mod size,循环队列:把队列设想成环形,让队列设想成环形,让sq【0】接在sq【M-1】之后,即:若rear+1M, 则另rear=0,移动指针不能用i=i+1,而是i=(i+1)%MAX
    入队 sq【rear】=e;
    rear=(rear+1)%M
    出队e=sq

第16章 树

  • 树的定义

根节点:唯一
节点的度:节点拥有的子树数。度为0:称为终端节点或叶节点
树的度:树内各节点的度的最大值
内部节点:除根节点外的节点
孩子(child):节点的子树的根 称为该节点的孩子,反过来,称为双亲(parent)
兄弟(sibling):同一双亲的孩子之间的关系
节点的祖先:从根到该节点所经分支上的全部节点
节点层次:根为第一层,根的孩子为第二层
树的深度(Depth):树中节点的最大层次

  • 树的基本操作
    查找类

插入类

删除类

  • 树的分类

满二叉树
如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。
如果一个二叉树的层数为K,且结点总数是(2^k) -1,则它就是满二叉树。
完全二叉树
它是由满二叉树而引出来的。
若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,
线索二叉树
n个结点的二叉链表中含有n+1(2n-(n-1)=n+1)个空指针域(就是用于指向左右孩子的域)。
利用二叉链表中的空指针域,存放指向结点在某种遍历次序下的前驱和后继结点的指针(这种附加的指针称为"线索")。
加上线索的二叉树称为线索二叉树。
哈夫曼树(霍夫曼树)又称为最优树

  • 树的遍历
    前序遍历:从根结点开始,访问每一个结点及其孩子。(A->B->D->E->C)
    Visit node
    Traverse(left child)
    Traverse(right child)
    中序遍历:从根结点开始,访问结点的左侧孩子,然后是该结点,再然后是任何剩余的结点。(D->B->E->A->C)
    Traverse(left child)
    Visit node
    Traverse(right child)
    后序遍历:从根结点开始,访问结点的孩子,然后是该结点。(D->E->B->C->A)
    Traverse(left child)
    Traverse(right child)
    Visit node
    层序遍历:从根节点开始,访问每一层的所有结点,一次一层。(A->B->C->D->E)

第17章 二叉查找树

  • 查找算法

  • 生成

  • 删除

  • 平衡二叉树

第18章 堆和优先队列

第19章 图

  • 图的结构构成

顶点(vertex):图中的数据元素

边(edge):图中连接这些顶点的线

  • 图的基本概念
    无向图

如果一个图结构中,所有的边都没有方向性,那么这种图便称为无向图。
有向图

一个图结构中,边是有方向性的,那么这种图就称为有向图。
顶点的度

连接顶点的边的数量称为该顶点的度。顶点的度在有向图和无向图中具有不同的表示。对于无向图,一个顶点V的度比较简单,其是连接该顶点的边的数量,记为D(V)。

对于有向图要稍复杂些,根据连接顶点V的边的方向性,一个顶点的度有入度和出度之分。

入度是以该顶点为端点的入边数量, 记为ID(V)。
出度是以该顶点为端点的出边数量, 记为OD(V)。

  • 常见图的算法
    广度优先遍历

遍历方法:从一个顶点开始,辐射状地优先遍历其周围较广的区域
实现方法:需要一个队列来保存遍历过的定点顺序,以便按出队的顺序再去访问这些顶点的邻接顶点
深度优先遍历

遍历方法:从一个顶点开始,沿边去探寻每一个顶点。(通俗一点:一条道走到黑!)
实现方法:通过栈来保存遍历过的定点顺序,遇到一个顶点,只是先获得它,并不出栈(因为要多次利用它),然后把它的第一个未被访问的节点入队列。如果没有相邻的未被访问的顶点,才把这个顶点出栈。

  • 最小生成树
    在连通网的所有生成树中,所有边的代价和最小的生成树,称为最小生成树。
  • Kruskal算法
    此算法可以称为“加边法”,初始最小生成树边数为0,每迭代一次就选择一条满足条件的最小代价边,加入到最小生成树的边集合里。
  • Prim算法
    此算法可以称为“加点法”,每次迭代选择代价最小的边对应的点,加入到最小生成树中。算法从某一个顶点s开始,逐渐长大覆盖整个连通网的所有顶点。

总结所做过的作业

1.任务1安装虚拟机

2.第一周作业

·对专业的认识和期望
·发表博客记录学习过程
·安装操作系统
·对于Linux 基础基础学习

3.课堂实践一

(1)任务1:使用VIM编辑器编写Java程序。要求输入2个Int类型的数值m和n,当m不为0时,计算(m!)+(m的n次方),并输出。当m为0时提示重新输入。
要求程序能够运行成功,否则后面均不得分。
①:程序运行结果截图(全屏截图+学号水印)(4分)
②:git push成功的截图(全屏截图+学号水印)(4分)
③:单步调试,查看当m=2时的m和n的中间值(可以使用locals或print等查看)(全屏截图+学号水印)(4分)

4.编写简单的类

5.复数计算器

6.类继承作业

7.栈实践

8.二分查找(折半查找)实践

9.排序

10.查找及ASL作业(计算)

11.树-计算题

12.二叉树的建立和层序遍历法实践

13.哈夫曼编码测试

14.地图染色问题

15.Dijkstra(迪杰斯特拉)算法测试

16.最小生成树测试

实验

实验一:Linux基础与Java开发环境

·基于命令行和IDE(Intellj IDEA 简易教程](http://www.cnblogs.com/rocedu/p/4421202.html)进行简单的Java程序编辑、编译、运行和调试。
·练习Linux基本命令;
·学习Java程序的JDB调试技能:https://www.cnblogs.com/rocedu/p/6371262.html
·编写简单的Java程序。

实验二:Java基础(数据/表达式、判定/循环语句)

· 编写简单的计算器,完成加减乘除模运算。
·要求从键盘输入两个数,使用判定语句选择一种操作,计算结果后输出,然后使用判定和循环语句选择继续计算还是退出。
·编写测试代码,测试验证。(https://www.cnblogs.com/rocedu/p/4472842.html)

实验三:面向对象程序设计

·初步掌握单元测试和TDD
·理解并掌握面向对象三要素:封装、继承、多态(自己去学!)
·初步掌握UML建模

实验四:Java Socket编程

·学习蓝墨云上教材《Java和Android编程》“第16章 输入/输出 ”和“第22章 网络”,学习JavaSocket编程
·结对编程。结对伙伴A编写客户端SocketClient.java,结对伙伴B编写服务器端。

实验五:Android程序设计

·Android Stuidio的安装测试:
·Activity测试
·UI测试
·布局测试
·事件处理测试

实验六:线性结构之链表

·链表练习

实验七:排序与查找

·定义一个Searching和Sorting类,并在类中实现linearSearch,SelectionSort方法,最后完成测试。
·重构你的代码
·参考http://www.cnblogs.com/maybe2030/p/4715035.html ,学习各种查找算法并在Searching中补充查找算法并测试
·补充实现课上讲过的排序方法:希尔排序,堆排序,二叉树排序等(至少3个)
·编写Android程序对实现各种查找与排序算法进行测试

实验八:哈夫曼编码测试

·参考教材PP16.1,完成链树LinkedBinaryTree的实现(getRight,contains,toString,preorder,postorder)
·基于LinkedBinaryTree,实现基于(中序,先序)序列构造唯一一棵二㕚树的功能,比如给出中序HDIBEMJNAFCKGL和后序ABDHIEJMNCFGKL,构造出附图中的树
·自己设计并实现一颗决策树
·输入中缀表达式,使用树将中缀表达式转换为后缀表达式,并输出后缀表达式和计算结果

实验九:

·图的综合实践
(1)初始化
(2)图的遍历
(3)完成有向图的拓扑排序
(4)完成无向图的最小生成树(Prim算法或Kruscal算法均可)

代码托管链接:https://gitee.com/besti1923/niu-zimeng-20192328/tree/master/src

给出statistic.sh的运行结果,说明本学期的代码量目标达到没有?


勉强达到目标

加点代码,改点代码是理解的最好方式,参考编程的智慧,谈谈你的心得

在已有代码的上并且可以很好的理解此代码的基础上,加点代码,改点代码比较容易。
我的心得是:
先把眼前的问题解决解决好,再考虑将来的扩展问题。
先写出可用的代码,再考虑是否需要拓展,继承等问题。
先写出可用,没有bug的代码,再考虑测试的问题。

积极主动敲代码做到没?教材实践上有什么经验教训?

在每次实验上都会花费大量的时间去敲代码,学习。但是是以实验作业为驱动自己学习的。以后应该更加积极主动。
可当实践的时候。老师可以带着敲代码感觉很好对于每一步都比较清晰,上完一节课感觉收获很大。不过在实践课上就需要更加专注不然很有可能就错过一部分。
在自己动手敲代码的时候需要思路清晰才能更好的进行。应该先构思好再动手会比较节约时间。

课程收获与不足

自己的收获(投入,效率,效果等)

在本课程收获很大,特别的是自己有了自学的意识。
在本课程投入的时间很多,收获也很大。

自己需要改进的地方

需要更加积极主动的学习。
及时查漏补缺。
增加自己的耐心。

问卷调查

你平均每周投入到本课程有效学习时间有多少?
大概20个小时左右。
每周的学习效率有提高吗?你是怎么衡量的?
有提高,在相同的时间可以学到的内容增多了,可以越来越有耐心的坐在那里敲代码,变得专注。
蓝墨云班课的使用对你的学习有促进吗?有什么建议和意见吗?
有促进,蓝墨云的使用感觉比较方便。
你觉得这门课老师应该继续做哪一件事情?
继续带领大家敲代码。
你觉得这门课老师应该停止做哪一件事情?
停止用英文考试,每次的考试都太难过了,瑟瑟发抖。

posted @ 2020-12-31 23:48  20192328牛梓萌  阅读(110)  评论(0编辑  收藏  举报