深浅模式
算法就是解决实际问题的过程和方法!就像我们用导航软件找最短路线一样,算法已经融入生活的方方面面。
无论是点外卖、刷短视频,还是做数据分析,算法都在悄悄影响着我们的选择和效率。
所以,学习算法能够锻炼系统化思考能力和编程思维。功利一点说,也是为了应付技术面试。
学习算法推荐两步:
- 理清每种算法的核心流程
- 动手写代码实现
排序算法
排序是把一组数据按照特定规则重新排列。比如我们生活中用导航软件找最短路线,其实背后也有排序算法在帮忙。
冒泡排序
每一轮遍历数组,把当前未排序部分中最大的元素“冒泡”到末尾。每完成一轮,未排序区间就缩小一格,直到全部有序。
简单流程如下:
- 从头到尾遍历数组,比较相邻元素,如果前面的比后面的大,就交换它们。
- 每一轮结束,最大的元素就被“冒泡”到末尾。
- 重复上述过程,直到没有需要交换的元素。
来看一个简化版的 Java 代码示例:
java
// 定义一个待排序数组
int[] arr = {5, 2, 3, 1};
// 外层循环控制轮数,arr.length - 1 防止数组越界
for (int i = 0; i < arr.length - 1; i++) {
// 内层循环控制每轮比较次数,再 -i 是为了只处理还没排好序的部分
for (int j = 0; j < arr.length - 1 - i; j++) {
// 如果前一个比后一个大,交换
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
这段代码每次都把当前未排序区间的最大值“推”到最后。输出结果就是一个升序排列的数组。
选择排序
每一轮从未排序区间中选出最小的元素,放到已排序区间的末尾。这样每轮都能确定一个最终位置的元素。
基本流程如下:
- 从头到尾遍历数组,假设当前位置 i 是最小值。
- 用一个内层循环,找出 i 之后最小的元素。
- 如果找到更小的,就和 i 位置交换。
- 重复上述过程,直到全部有序。
来看一个简化版的 Java 代码示例:
java
// 定义一个待排序数组
int[] arr = {5, 1, 3, 2};
// 外层循环控制轮数
for (int i = 0; i < arr.length - 1; i++) {
int minIndex = i; // 记录本轮最小值的索引
// 内层循环找出最小值,i + 1为了只在还没排好序的部分里找最小值
for (int j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
// 只和最小值交换一次,减少不必要的交换
if (minIndex != i) {
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
这种写法相比“每遇到更小的就交换”更高效,因为每轮只发生一次交换,避免了大量无意义的操作。
查找算法
查找是在一组数据中快速定位到目标元素。一般来说,查找操作通常发生在数据已经排好序之后,这样才能用更高效的查找方式。
基本/顺序查找
最直接的查找方式,就是顺序查找——从头到尾一个个比对,直到找到目标或者遍历结束。这种方法实现简单,但当数据量很大时,效率会非常低,最坏情况下需要遍历整个数组。
来看一个简单的伪代码示例:
java
// 顺序查找
int[] arr = {7, 23, 79, 81, 103, 127, 131, 147};
int target = 81;
for (int i = 0; i < arr.length; i++) {
if (arr[i] == target) {
// 找到了,返回下标
return i;
}
}
// 没找到,返回-1
return -1;
这种查找方式适合数据量小、或者数据本身无序的场景。
二分查找
当数据已经有序时,二分查找(折半查找)能大幅提升查找效率。它的核心思想是:每次都把查找区间一分为二,逐步缩小范围,直到找到目标或区间为空。
二分查找的流程如下:
- 设定头指针
left
和尾指针right
,初始分别指向数组两端。 - 计算中间位置
middle
。 - 比较目标值和中间元素:
- 如果目标比中间值大,说明目标在右半区间,更新
left = middle + 1
。 - 如果目标比中间值小,说明目标在左半区间,更新
right = middle - 1
。 - 如果相等,直接返回中间下标。
- 如果目标比中间值大,说明目标在右半区间,更新
- 重复上述过程,直到
left > right
,说明查找结束。
来看一个标准的 Java 代码实现:
java
// 二分查找
public static int searchDataIndex(int[] array, int number) {
int left = 0;
int right = array.length - 1;
while (left <= right) {
int middle = (left + right) / 2;
if (number > array[middle]) {
left = middle + 1;
} else if (number < array[middle]) {
right = middle - 1;
} else {
return middle; // 找到目标,返回下标
}
}
return -1; // 没找到
}
二分查找会遇到的极端情况:
- 目标不存在:如果目标值不在数组中,最终 left 会大于 right,循环结束,返回 -1,表示没找到。
- 数组为空:如果数组长度为 0,right 初始就是 -1,循环根本不会进入,直接返回 -1。
- 溢出问题:在极大数组下,比如超过了 int 能表示的最大值的情况下,(left + right) / 2 可能会溢出。更安全的写法是 left + (right - left) / 2,但一般面试和日常开发中,普通写法就够用了。
二分查找的效率远高于顺序查找,尤其是在大数据量场景下,查找次数大大减少。
评论