最近在学习算法,选用的是《算法题解》这本书,作为算法的入门书籍。为了以后方便复习以及加强记忆,每次看完一章以后都会把知识点记录到这个文章当中。本文的结构会参考《算法图解》的目录结构,方便自己记录。在文章中,可能会有一些算法有LZ自己简单实现的算法代码,但部分算法没有具体的代码实现,因此仅供参考。
文章中的指的都是,算法速度用大O表示法来表示。
目录
算法:
1、二分查找(折半查找)
2、选择排序
3、快速排序
4、广度优先搜索
5、迪克斯特拉算法
6、贪婪算法
7、K最近邻算法(KNN)
文章相关知识点
使用场景:在一个有序的元素列表中,查询某个数据所在的位置。
具体思想:
1.确定查找范围front=0,end=N-1,计算中项mid=(front+end)/2。
2.若a[mid]=x或front>=end,则结束查找;否则,向下继续。
3.若a[mid]
时间复杂度:O()
简单代码实现:
/**
* 用二分法查询数据在数组中的位置,当数据存在时,返回数据所在角标,不存在时,返回-1
*
* @param array 被查询的有序数组
* @param value 要查询的数据
* @return 查询结果
*/
public static int binary(int[] array, int value) {
int low = 0;
int high = array.length - 1;
while (high >= low) {
int mid = (low + high) / 2;
if (array[mid] == value) {
return mid;
} else if (array[mid] > value) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return -1;
}
使用场景:将一个元素列表,按照一定的要求进行排序
具体思想:
1、从待排序元素列表中找到最小(或最大)的元素,放到有序数组中末尾。
2、对剩余的元素重复步骤1,直到待排序的元素列表中的元素全部放到有序数组中。
时间复杂度:O()
简单代码实现:
/**
* 将一个无序int数组从小到大排序
*
* @param array 要排序的int数组
* @return 查询结果
*/
public static int[] selectSort(int[] array) {
int minIndex = 0;
int temp = 0;
for (int i = 0; i < array.length; i++) {
//获取要查询无序数组的第一个角标
minIndex = i;
for (int j = i; j < array.length; j++) {
//找到无序数组的最小值角标,并保存
if (array[minIndex] > array[j]) {
minIndex = j;
}
}
//将要查询数组第一个值与最小值交换,无序数组长度减少,前面的都是有序数组
temp = array[i];
array[i] = array[minIndex];
array[minIndex] = temp;
}
return array;
}
使用场景:将一个元素列表,按照一定的要求进行排序
具体思想:
1、选择基准值。
2、将元素列表分为两个子列表:小于基准值和大于基准值。
3、对这两个子数组再次进行步骤1-2操作
时间复杂度:O()
简单代码实现:
/**
* 对数组进行从小到大排序
*
* @param array 要排序的数组
* @param low 要从数组哪一位开始排序
* @param high 排序位置要截止到数组的哪一位
*/
public static void quickSort(int[] array, int low, int high) {
//判断数组是否需要排序
if (low < high) {
//将元素列表分为两个子列表:小于基准值和大于基准值,并返回基准值所在的位置
int middle = getMid(array, low, high);
//对小于基准值的数组再次排序
quickSort(array, low, middle - 1);
//对大于基准值的数组再次排序
quickSort(array, middle + 1, high);
}
}
/**
* 将数组按照基准值分为大于基准值和小于基准值两部分,并返回基准值所在的坐标
*
* @param array 要排序的数组
* @param low 要从数组哪一位开始排序
* @param high 排序位置要截止到数组的哪一位
* @return 基准值所在的角标
*/
public static int getMid(int[] array, int low, int high) {
//数组的第一个作为基准值
int tmp = array[low];
//对数组中的值进行遍历
while (low < high) {
//从右往左找比基准值小的数
while (low < high && array[high] >= tmp) {
high--;
}
//将找到的比基准值小的数插在左端
array[low] = array[high];
//从左往右找比基准值大的数
while (low < high && array[low] < tmp) {
low++;
}
//将找到的比基准值大的数插在右端
array[high] = array[low];
}
//将基准值插到已经分好大小的数组中间
array[low] = tmp;
//返回基准值目前所在的位置
return low;
}
使用场景:解决路径最短问题。(1)从节点A出发,又到达节点B的路径吗?(2)从节点A出发,到达节点B的哪条路径最短?
具体思想:从图中某顶点v出发,在访问了v之后依次访问v的各个未曾访问过的邻接点,然后分别从这些邻接点出发依次访问它们的邻接点,并使得“先被访问的顶点的邻接点先于后被访问的顶点的邻接点被访问,直至图中所有已被访问的顶点的邻接点都被访问到。如果此时图中尚有顶点未被访问,则需要另选一个未曾被访问过的顶点作为新的起始点,重复上述过程,直至图中所有顶点都被访问到为止。
使用场景:找出总权重最小的路径。
注意事项:只适合有向无环图,并且不能用于包含负权边的图。
具体思想:
(1)找出最便宜的节点,即可在短时间内前往的节点。
(2)对于该节点的邻居,检查是否有前往她们的更短路径,如果有,就更新其开销。
(3)重复这个过程,直到对图中的每个节点都这么做。
(4)计算最终路径。
使用场景:解决NP完全问题(没有快速算法的问题),寻找局部最优解,企图以这种方式获取全局最优解
具体思想:对于一些NP完全问题,最佳的做法是使用近似算法,找到和最优解差不多的结果。
使用场景:对数据进行分类(编组)和回归(预测结果)
具体思想:对事物进行特征抽取,转换成一系列可比较的数字。
这里是《算法图解》中提到的额外的知识点,有助于了解和学习算法:
1、大O表示法含义
2、D&C(分而治之)原理
3、递归原理
4、内存工作原理
5、数组和链表结构
6、调用栈过程
7、散列表原理
8、欧几里得定律
9、队列和栈结构
10、判断什么是NP问题
11、动态规划使用方法和局限性
12、提到但没介绍内容:B树,红黑树,堆,伸展树,反向索引,傅里叶算法,并行算法