(前面的准备工作)环境搭建
- 配置Java环境,安装Eclipse,以及下载书籍配套的测试文件和需要引用到的algs.jar包请参考:
https://www.cnblogs.com/kylinlin/p/6253362.html
algs.jar 需要配置到两个地方,第一是放到jdk/jre/lib/ext下,这样可保证通过Eclipse Terminal运行时正常。第二是,在Eclipse中的工程的BuildPath中,添加External Jar,这样在Eclipse代码中就不会编译报错说“StdIn is not API”之类的。
-
我用的开发工具是Eclipse,如果自己的Eclipse中window--show view 中没有terminal,请在help中的Eclipse Market中下载Eclipse TM Terminal(大致叫这个名字,使用人很多)。
-
Terminal连接配置
这个编码格式GBK或者UTF-8可以根据自己的系统而定。
-
测试
如上图,右键src目录下打开terminal,依次执行javac chapter01/BinarySearch.java ,然后是红色方框中的java命令后,控制台会输出如上数字时,我们的环境和工具已经准备好啦。
javac chapterBinarySearch.java
java chapter01.BinarySearch largeW.txt < largeT.txt
-
-
那么如果是用IDEA呢?如果是linux系统呢?
linux系统配置JDK:https://blog.csdn.net/zbj18314469395/article/details/86064849
配置好以后,javac -version java -version 都没有问题。但是,当使用IDEA的Terminal或linux的Terminal时,对.class文件使用java xxx 时,就会出现
Error:Could not find or load main class xxx
我快疯了。
IDEA 默认src目录作为
source root
,也就是当你在src目录下打开终端时,就没问题了。xxx src$:java xxx
这样就可以了。
1.1基础编程模型
我们把描述和实现算法所用到的语言特性、软件库和操作系统特性总称为基础编程模型。
1.1.1 Java程序的基本结构
- 原始数据类型:它们在计算机程序中精确地定义整数、浮点数和布尔值等。它们的定义包括取值范围和能够对相应的值进行操作,它们能够被组合为类似数学公式定义的表达式。
- 语句:语句通过创建变量并对其赋值、控制运行流程或者引发副作用来进行计算。我们会使用到的六种语句:声明、赋值、条件、循环、调用和返回。
- 数组:数组是多个同种数据类型的集合。
- 静态方法:静态方法可以封装并重用代码,使我们可以用独立的模块开发程序。
- 字符串:字符串是一连串的字符,Java内置了对它们的一些操作。
- 标准输入、输出:标准输入输出是程序与外界联系的桥梁。
- 数据抽象:数据抽象封装和重用代码,使我们可以定义非原始数据类型,进而支持面向对象编程。
1.1.2 Java原始数据类型与表达式
- 整型 int
- 双精度实数类型 double
- 布尔型 boolean
- 字符型 char
1.1.3 语句
- 声明语句
- 赋值语句
- 条件语句
- 循环语句
- 调用和返回语句
1.1.4 简便记法
- 声明并初始化
int i = 1
- 隐式赋值
++i--ii++i--
以及+=...
一元和二元运算符 - 单语句代码块
- for语句
1.1.5 数组
1.1.6 静态方法
1.1.7 API
1.1.8 字符串
1.1.9 输入输出
Java程序可以从命令行参数或者一个名为标准输入流的抽象字符流中获得输入,并将输出写入另一个名为标准输出流的字符流中。
操作系统常用命令
命令 | 参数 | 含义 |
---|---|---|
javac | .java文件名 | 编译Java程序 |
java | .class文件名(不需要扩展名)和命令行参数 | 运行Java程序 |
more | 任意文本文件名 | 打印文件内容 |
命令解析
% java RandomSeq 5 100.0 200.0
%
:提示符
java
:调用Java
RandomSeq
:调用RandomSequence中的静态方法main()
5 100.0 200.0
:分别表示args[0] args[1] args[2]
标准输出
print(String s)
println(String s)
println()
printf(String f, ,,,)
格式化输出
package chapter01;
//import edu.princeton.cs.algs4.*;
public class RandomSeq {
public static void main(String[] args) {
// 打印N个(lo, hi)之间的随机值
int N = Integer.parseInt(args[0]);
double lo = Double.parseDouble(args[1]);
double hi = Double.parseDouble(args[2]);
for (int i = 0; i < N; i++) {
double x = StdRandom.uniform(lo, hi);
StdOut.printf("%.2f
", x);
}
}
}
以上代码,在Eclipse的终端里执行javac 编译时,会报
解决方法如下:
package chapter01;
import edu.princeton.cs.algs4.*; // 需要导入包,即可通过javac 编译
public class RandomSeq {
public static void main(String[] args) {
// 打印N个(lo, hi)之间的随机值
int N = Integer.parseInt(args[0]);
double lo = Double.parseDouble(args[1]);
double hi = Double.parseDouble(args[2]);
for (int i = 0; i < N; i++) {
double x = StdRandom.uniform(lo, hi);
StdOut.printf("%.2f
", x);
}
}
}
执行结果:
D:Softeclipse_rcp_workplacealgorithms4src>java chapter01.RandomSeq 5 100.0 200.0
123.26
148.20
156.28
116.85
183.34
标准输入
package chapter01;
import edu.princeton.cs.algs4.*;
public class Average {
public static void main(String[] args) {
// 取StdIn中所有数的平均值
double sum = 0.0;
int cnt = 0;
while (!StdIn.isEmpty()) {
// 读取一个数并计算累计之和
sum += StdIn.readDouble();
cnt++;
}
double avg = sum / cnt;
StdOut.printf("Average is %.5f
", avg);
}
}
StdIn用例举例及运行结果
D:Softeclipse_rcp_workplacealgorithms4src>java chapter01.Average
1.23456
2.34567
3.45678
4.56789
^Z
Average is 2.90123
需要注意:默认状态下系统会将标准输出重定向到终端窗口——你输入的内容就是输入流(由ctrl-d或ctrl-z
结束,取决于你使用的终端),在Eclipse的cmd终端中,输入结束后,Ctrl+Z 然后Enter回车即可
重定向与管道
重定向: < >
java chapter01.RandomSeq 1000 100.0 200.0 > data.txt
这条命令指明标准输出流不是被打印至终端窗口,而是被写入一个叫做data.txt的文件。
java chapter01.Average < data.txt
“<”号是一个提示符,它告诉操作系统读取文本文件data.txt作为输入流而不是在终端窗口等待用户的输入。
管道: | 将一个程序的输出重定向为另一程序的输入叫做管道
java chapter01.RandomSeq 1000 100.0 200.0 | java chapter01.Average
这条命令将RandomSeq的标准输出和Average的标准输入指定为同一个流。
它的效果好像是在Average运行时RandomSeq将它生成的数字输入到了终端窗口。这种差别影响非常深远,因为它突破了我们能够处理的输入输出的长度限制。
当RandomSeq调用StdOut.println()时,它就向输出流的末尾添加了一个字符;当Average调用StdIn.readInt()时,它就从输入流的开头删除了一个字符串。
这些动作发生的实际顺序取决于操作系统:它可能会先运行RandomSeq并产生一些输出,然后在运行Average,来消耗这些输出,或者它也可以先运行Average,直到它需要一些输入然后再运行RandomSeq来产生一些输出。
虽然最后的结果都一样,但我们的程序就不需要担心这些细节,因为它们只会和标准输入和标准输出的抽象打交道。
小结:
将一个文件重定向为标准输入
java chapter01.Average < data.txt
data=>operation: data.txt
stdIn=>operation: 标准输入
avg=>operation: Average
data->stdIn->avg
将标准输出重定向到一个文件
java chapter01.RandomSeq 1000 100.0 200.0 > data.txt
data=>operation: data.txt
stdOut=>operation: 标准输出
randomReq=>operation: RandomReq
randomReq->stdOut->data
将一个程序的输出通过管道作为另一程序的输入
java chapter01.RandomSeq 1000 100.0 200.0 | java chapter01.Average
avg=>operation: Average
stdOut=>operation: 标准输出
stdIn=>operation: 标准输入
randomReq=>operation: RandomReq
randomReq->stdOut->stdIn->avg
用Markdown画流程图时,不支持flowsequence,而支持mermaid语法。
mermaid [ˈmɜːrmeɪd] 意为‘传说中的美人鱼’
1.1.10 二分查找
package chapter01;
import java.util.Arrays;
import edu.princeton.cs.algs4.*;
public class BinarySearch {
public static int rank(int key, int[] a) {
// 数组必须是有序的
int lo = 0;
int hi = a.length - 1;
while (lo <= hi) {
// 被查找的键要么不存在,要么必然存在于a[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) < 0) {
StdOut.println(key);
}
}
}
}
终端
D:Softeclipse_rcp_workplacealgorithms4src>java chapter01.BinarySearch tinyW.txt < tinyT.txt
50
99
13
大数据量测试 largeW.txt中有100万个int值,largeT中有1000万个int值
D:Softeclipse_rcp_workplacealgorithms4src>java chapter01.BinarySearch largeW.txt < largeT.txt
......
29798919
9505145
32449528
38862597
69830567
1.1.11 展望
数据抽象,也就是非原始数据类型啦,自定义的复杂的。