1. Java基础算法实战:从入门到精通的必经之路
作为一名从零开始自学Java的老程序员,我深知算法学习过程中"动手敲代码"的重要性。很多初学者喜欢看视频、读理论,但真正自己动手时却漏洞百出。今天我就用两个最基础的算法案例——身高比较和数字整除判断,带大家体验真实的编程学习过程。这两个案例看似简单,却能暴露出新手常见的思维盲区。
2. 案例一:身高比较算法的实现与优化
2.1 基础实现方案
我们先来看第一个案例:比较两个人的身高并输出结果。这个需求听起来简单到甚至不像个"算法",但正是这种基础练习最能培养编程思维。以下是基础实现代码:
java复制import java.util.Scanner;
public class HeightComparator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入第一个人的身高(cm): ");
double height1 = scanner.nextDouble();
System.out.print("请输入第二个人的身高(cm): ");
double height2 = scanner.nextDouble();
if (height1 > height2) {
System.out.println("第一个人更高");
} else if (height1 < height2) {
System.out.println("第二个人更高");
} else {
System.out.println("两人一样高");
}
}
}
注意:使用Scanner获取用户输入时要注意处理InputMismatchException异常,实际项目中必须添加异常处理逻辑。
2.2 常见问题与边界情况处理
在实际教学中,我发现新手常犯以下几个错误:
-
数据类型选择不当:有人会用int类型存储身高,这就无法表示168.5cm这样的常见身高值。浮点数比较时还要注意精度问题,比如用
==判断两个浮点数是否相等可能得到错误结果。 -
输入验证缺失:用户可能输入负数或非数字字符,程序会直接崩溃。完善的代码应该添加输入验证:
java复制// 改进的输入验证
while (true) {
try {
System.out.print("请输入第一个人的身高(cm): ");
double height = scanner.nextDouble();
if (height <= 0) {
System.out.println("身高必须为正数!");
continue;
}
height1 = height;
break;
} catch (InputMismatchException e) {
System.out.println("请输入有效的数字!");
scanner.next(); // 清除错误输入
}
}
- 比较逻辑不严谨:初学者容易漏掉相等的情况,只写if-else而没有else if分支。
2.3 算法扩展与优化
掌握了基础版本后,我们可以进行以下扩展:
- 多人身高比较:使用数组存储多个人的身高,找出最高和最矮的
- 添加单位转换:同时支持厘米和英尺英寸的输入
- 面向对象重构:创建Person类封装身高属性和比较逻辑
java复制// 面向对象版本示例
class Person {
private double height;
public Person(double height) {
this.height = height;
}
public String compareHeight(Person other) {
if (this.height > other.height) return "更高";
if (this.height < other.height) return "更矮";
return "一样高";
}
}
3. 案例二:三位数整除判断的两种实现方式
3.1 方法一:直接取模运算
判断一个三位数能否被3整除,最直接的方法是使用取模运算符(%):
java复制public static boolean isDivisibleBy3_mod(int number) {
if (number < 100 || number > 999) {
throw new IllegalArgumentException("请输入三位数");
}
return number % 3 == 0;
}
技巧:在方法开头添加参数校验是好习惯,可以避免后续计算出现意外结果。
3.2 方法二:数字和法(数学原理)
第二种方法利用了数学上的一个性质:如果一个数的各位数字之和能被3整除,那么这个数本身也能被3整除。实现代码如下:
java复制public static boolean isDivisibleBy3_sum(int number) {
if (number < 100 || number > 999) {
throw new IllegalArgumentException("请输入三位数");
}
int sum = 0;
int temp = number;
while (temp > 0) {
sum += temp % 10;
temp /= 10;
}
return sum % 3 == 0;
}
3.3 两种方法的对比分析
| 比较维度 | 取模法 | 数字和法 |
|---|---|---|
| 性能 | O(1)时间复杂度 | O(n)时间复杂度(n为数字位数) |
| 可读性 | 直观简单 | 需要理解数学原理 |
| 扩展性 | 仅适用于模运算 | 可扩展其他整除特性判断(如9) |
| 适用场景 | 一般情况首选 | 需要展示算法思维时使用 |
在实际工程中,直接使用取模法是更好的选择。但学习算法时,了解数字和法有助于培养数学思维,这对解决更复杂的问题很有帮助。
3.4 常见实现错误
- 位数验证缺失:没有检查输入是否为三位数
- 负数处理不当:对于负数输入,数字和法可能出错
- 边界条件遗漏:没有测试100和999这两个边界值
- 循环终止条件错误:在数字和法中,while循环条件写错导致无限循环
4. 算法学习的方法论与实战建议
4.1 为什么必须动手敲代码
看懂了≠会写了,这是算法学习最大的误区。只有亲手实现时才会遇到:
- 语法细节问题(如Scanner的使用)
- 边界条件处理(如输入验证)
- 调试技巧培养(如断点调试)
建议每个算法至少实现三遍:
- 按照思路自己实现
- 参考优化版本重写
- 隔一段时间后重新实现
4.2 调试技巧与单元测试
养成写单元测试的习惯,使用JUnit测试各种边界情况:
java复制@Test
public void testIsDivisibleBy3() {
assertTrue(Algorithms.isDivisibleBy3_mod(123));
assertFalse(Algorithms.isDivisibleBy3_mod(122));
assertTrue(Algorithms.isDivisibleBy3_sum(999));
assertFalse(Algorithms.isDivisibleBy3_sum(100));
// 测试异常情况
assertThrows(IllegalArgumentException.class, () -> {
Algorithms.isDivisibleBy3_mod(99);
});
}
4.3 算法复杂度分析入门
即使是简单算法,也要培养复杂度分析的意识:
- 取模法:无论输入大小,操作次数固定 → O(1)
- 数字和法:循环次数与数字位数成正比 → O(n)
了解这些概念对后续学习高级算法至关重要。
5. 从基础到进阶的学习路径
掌握了这些基础算法后,建议按照以下路径继续学习:
- 数据结构基础:数组、链表、栈、队列的实现与应用
- 排序算法:冒泡、选择、插入排序的实现与比较
- 递归与分治:斐波那契数列、汉诺塔等问题
- 常见算法范式:贪心算法、动态规划、回溯法等
记住,每个阶段都要像今天这样从小案例开始,逐步深入。我个人的经验是,坚持每天实现一个小算法,半年后就会有质的飞跃。当初我自学Java时,就是从这样的身高比较程序开始,现在已经成为专业开发者。关键是要保持coding的手感,遇到问题就查资料、调试,这种能力比单纯记住算法更重要。