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章 二叉查找树
-
查找算法
-
生成
-
删除
-
平衡二叉树
{{uploading-image-610403.png(uploading...)}}
第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分)
实验
实验一: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个小时左右。
每周的学习效率有提高吗?你是怎么衡量的?
有提高,在相同的时间可以学到的内容增多了,可以越来越有耐心的坐在那里敲代码,变得专注。
蓝墨云班课的使用对你的学习有促进吗?有什么建议和意见吗?
有促进,蓝墨云的使用感觉比较方便。
你觉得这门课老师应该继续做哪一件事情?
继续带领大家敲代码。
你觉得这门课老师应该停止做哪一件事情?
停止用英文考试,每次的考试都太难过了,瑟瑟发抖。