『算法』读书笔记 1.1基础编程模型
Algorithms Fourth Edition
Chapter 1
本章结构
1.1 Java语法
1.2数据抽象
1.3集合类抽象数据类型:背包 (Bags) 、队列 (Queues) 、栈 (Stacks)
1.4面向操作的抽象数据类型
1.5连通性问题-Case Study: Union - Find ADT
1.1 Basic Programming Model
『一段Java程序(类)是一个静态方法(函数)类,或者定义了一个数据类型。』
l Primitive Data Type 原始数据类型
long(64位整数);int(32位整数,能表示232个数值); byte(8位整数)
double为双精度实数(64位);float为32位单精度实数;char(16位字符)
l Statements 语句
a) Declaration 声明语句(Java编译器会检查类型一致性)
b) Assignment 赋值语句
c) Conditional 条件语句
d) Loops 循环语句 (for语句相当于是while语句的简化版)
e) Call & Return 调用和返回语句 - 和静态方法有关
简便记法:
1. Initializing declaration 声明并初始化
2. Implicit Assignments 隐式赋值
a = ++i 等价于 i = i+1; a = i(先i自增再赋值给a)
a = i++ 等价于 a = i; i = i +1(赋值给a后i再自增)
3. Single - Statement blocks 单语句代码段
l Arrays 数组
a) 访问数组中某个元素的方法是将其编号然后索引 number and then index them
b) 使用关键字new创建数组,需要在运行是明确创建数组
c) 一定要依次声明、创建并初始化数组 DON’T OMIT ANY ONE STEP!!!
d) 【code】颠倒数组元素顺序
int N = a.length;
for (int i = 0; i < N / 2; i++)
{
double temp = a[i];
a[i] = a[N-i-1];
a[N-i-1] = temp;
}
e) 【code】矩阵相乘(方阵) a[][] * b[][] = c[][]
int N = a.length;
double [][] c = new double[N][N];
for (int i = 0; i < a.length; i++)
for(int j = 0; j < a.length; j++)
{
for (int k = 0; k < N; k++)
c[i][j] += a[i][k] * b[k][j];
}
f) 数组名表示的是整个数组 - 数组是引用类型。如果需要复制数组,应通过重新创建并初始化一个新数组,然后将数组中的元素值挨个赋值到新数组的方式。
g) 二维数组:M X N数组,第一维是行数,第二维是列数
l Static Method 静态方法
a) 静态方法被成为函数,因为他们和数学函数的性质类似
b) 方法封装encapsulate了一系列语句所描述的运算。方法需要参数并根据参数计算出某种数据类型的返回值或者产生某种副作用
c) 【code】典型静态方法的实现:
判断一个数是否是素数
public static boolean isPrime(int N)
{
if (N < 2) return false
for(int i = 2; i * i < N; i++)
if ( N % i == 0) return false;
return ture;
}
计算平方根(牛顿迭代法) – 不是很明白 P13
计算调和级数
public static double H(int N)
{
double sum = 0.0;
for(int i = 1; i < N; i++)
sum += 1.0 / i;
return sum;
}
d) 方法的性质:
n 参数按值传递
n 方法名可以被重载
e) 方法只能返回一个值,但可以包含多个返回语句
f) 递归Recursionn:自己调用自己
使用递归的原因:1.递归代码比相应的非递归代码更加简洁易懂;2.可以使用数学模型来估计程序的性能
编写递归代码需要注意:1.方法的第一条语句总是包含一个return;2.递归调用总是去尝试解决一个规模更小的问题;3.递归调用的父问题和尝试解决的子问题不应该有交集
i) 单元测试:Java编程的最佳实践之一就是每个静态方法库中都包含一个main()函数来测试库中的所有方法
j) API的目的:seperate the client from the implementation
k) String 字符串
注意String类型不是原始的数据类型
类型转换API
l Standard I/O 标准输入/输出
格式化输出: printf()方法接受两个参数,前一个是格式字符串,如("%14d", x)
在%和转换代码(int d;double f, e;String s)之间可以插入一个整数来表示转换之后值的宽度。如果想在右边加入空格则应该使用负宽度。在宽度之后还可以插入一个小数点以及一个数值来制定转化后的double值保留的小数位数(精度)或者是String字符串所截取的长度。eg: "%14.4e" ==" 1.5952e+03" 此处用科学记号(指数)法表示数字,以E+n取代部分数字。
重定向和管道 Redictrction and Piping:将标准输入输出重定向到一个文件
% java RandomSeq 100 100.0 200.0 > data.txt //write into docs
% java Average < data.txt //Read from docs
% java RandomSeq 1000 100.0 200.0 | java average
//将一个程序的输出通过管道作为另一个程序的输入
l Data Abstraction 数据抽象
也被称为『面向对象编程』,优点:
允许通过模块化编程复用代码;
更容易构造链式数据结构linked data structure;
(链式数据存储是在计算机中用一组任意的存储单元存储线性表的数据元素,不要求逻辑上相邻的元素在物理位置上也相邻,因此没有顺序存储结构所具有的弱点,但同时也失去了顺序表可随机存取的优点。
l 二分查找
基本原理:
a) 假设表中元素是升序排列的,将表中间位置的关键字与需要查找的关键字进行比较,若一致则退出查找;
b) 如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则查找后一子表;
c) 重复步骤2直到两者相等为止
【code】:
import java.util.Arrays;
public class BinarySearch
{
public static int rank(int key, int[] a)
{
int lo = 0;
int hi = a.length -1;
while (lo <= hi)
{
int mid = lo + (hi - lo) / 2;
//此处是将浮点型转换为整型,会截断小数部分而非四舍五入
if (key < a[mid]) hi = mid -1;
else if (key > a[mid]) lo = mid +1;
else return mid;
}
return -1;
}
public static void main(String[] args)
{
int[] whitelist = In.readInts(args{0});
Arrays.sort(whitelist);
while (!StdIn.IsEmpty())
{
int key = StdIn.readInt();
if (rank(key, whitelist) == -1)
StuOut.printIn(key);
}
}
}
% java BinarySearch tinyW.txt < tinyT.txt
50
99
13
// 1.tinyW.txt为白名单文件,先对其进行排序;
2.重定向输入流,以tinyT.txt作为输入而不是在终端进行用户输入;
3.依次检测tinyT.txt的每一条记录,若未能在白名单中找到,则打印该记录