最近在學習算法,選用的是《算法題解》這本書,作爲算法的入門書籍。爲了以後方便複習以及加強記憶,每次看完一章以後都會把知識點記錄到這個文章當中。本文的結構會參考《算法圖解》的目錄結構,方便自己記錄。在文章中,可能會有一些算法有LZ自己簡單實現的算法代碼,但部分算法沒有具體的代碼實現,因此僅供參考。
文章中的指的都是,算法速度用大O表示法來表示。
目錄
算法:
1、二分查找(折半查找)
使用場景:在一個有序的元素列表中,查詢某個數據所在的位置。
具體思想:
1.確定查找範圍front=0,end=N-1,計算中項mid=(front+end)/2。
2.若a[mid]=x或front>=end,則結束查找;否則,向下繼續。
3.若a[mid]<x,說明待查找的元素值只可能在比中項元素大的範圍內,則把mid+1的值賦給front,並重新計算mid,轉去執行步驟2;若a[mid]>x,說明待查找的元素值只可能在比中項元素小的範圍內,則把mid-1的值賦給end,並重新計算mid,轉去執行步驟2。
時間複雜度: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;
}
2、選擇排序
使用場景:將一個元素列表,按照一定的要求進行排序
具體思想:
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;
}
3、快速排序
使用場景:將一個元素列表,按照一定的要求進行排序
具體思想:
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;
}
4、廣度優先搜索
使用場景:解決路徑最短問題。(1)從節點A出發,又到達節點B的路徑嗎?(2)從節點A出發,到達節點B的哪條路徑最短?
具體思想:從圖中某頂點v出發,在訪問了v之後依次訪問v的各個未曾訪問過的鄰接點,然後分別從這些鄰接點出發依次訪問它們的鄰接點,並使得“先被訪問的頂點的鄰接點先於後被訪問的頂點的鄰接點被訪問,直至圖中所有已被訪問的頂點的鄰接點都被訪問到。如果此時圖中尚有頂點未被訪問,則需要另選一個未曾被訪問過的頂點作爲新的起始點,重複上述過程,直至圖中所有頂點都被訪問到爲止。
5、迪克斯特拉算法
使用場景:找出總權重最小的路徑。
注意事項:只適合有向無環圖,並且不能用於包含負權邊的圖。
具體思想:
(1)找出最便宜的節點,即可在短時間內前往的節點。
(2)對於該節點的鄰居,檢查是否有前往她們的更短路徑,如果有,就更新其開銷。
(3)重複這個過程,直到對圖中的每個節點都這麼做。
(4)計算最終路徑。
6、貪婪算法
使用場景:解決NP完全問題(沒有快速算法的問題),尋找局部最優解,企圖以這種方式獲取全局最優解
具體思想:對於一些NP完全問題,最佳的做法是使用近似算法,找到和最優解差不多的結果。
7、K最近鄰算法(KNN)
使用場景:對數據進行分類(編組)和迴歸(預測結果)
具體思想:對事物進行特徵抽取,轉換成一系列可比較的數字。
文章相關知識點
這裏是《算法圖解》中提到的額外的知識點,有助於瞭解和學習算法:
1、大O表示法含義
2、D&C(分而治之)原理
3、遞歸原理
4、內存工作原理
5、數組和鏈表結構
6、調用棧過程
7、散列表原理
8、歐幾里得定律
9、隊列和棧結構
10、判斷什麼是NP問題
11、動態規劃使用方法和侷限性
12、提到但沒介紹內容:B樹,紅黑樹,堆,伸展樹,反向索引,傅里葉算法,並行算法