排序和查詢 {ignore}
排序演算法
排序演算法沒有優劣之分,在不同的場景中,不同的排序演算法執行效率不同。
- 選擇排序 Selection Sort
一次選擇排序,可以將某個區間的最小值排列到該區域的第一位,具體的方式是:
- 找出該區域的最小值
- 將該值與該區域第一個值交換
- 對下一個區域重複上述過程,直到排序完成
- 氣泡排序 Bubble Sort
一次氣泡排序,可以將某個區域序列的最大值排序到該區域的最後一位,具體的方式是:
- 將第1位和第2位比較,如果前者比後者大則交換
- 將第2位和第3位比較,如果前者比後者大則交換
- 依次類推,直到比較到該區域的最後兩位
- 重複上述過程,直到序列排序完成
- 插入排序 Insertion Sort
將序列分為兩個部分,一部分是有序的,一部分是無序的,現在要做的是,就是不斷的從無序的部分取出資料,加入到有序的部分,直到整個排序完成
例如:序列[5, 7, 2, 3, 6]
- 分為有序的序列和無序的序列 (5) (7 2 3 6)
- 不斷的擴充有序序列 (5 7) (2 3 6)
- 不斷的擴充有序序列 (2 5 7) (3 6)
- 不斷的擴充有序序列 (2 3 5 7) (6)
- 不斷的擴充有序序列 (2 3 5 6 7)
- 排序完成
- 快速排序 Quick Sort
選擇一個數(比如序列的最後一位)作為基準數,將整個序列排序成兩部分,一部分比該數小,另一部分比該數大,基準數在中間,然後對剩餘的序列做同樣的事情,直到排序完成
例如:序列[5, 7, 2, 3, 6, 4]
- 選擇4作為基準數,排序成為:(3, 2) 4 (7, 6, 5)
- 對於3,2, 繼續使用該方式排序,得到: (2, 3) 4 (7,6,5)
- 對於7,6,5,繼續使用該方式排序,得到: (2, 3) 4 (5,6,7)
- 排序完成
查詢演算法
- 順序查詢 Inorder Search
即普通的遍歷,屬於演算法的窮舉法,沒啥好解釋的
- 二分查詢 Binary Search
如果一個序列是一個排序好的序列,則使用二分查詢可以極大的縮短查詢時間
具體的做法是:
查詢該序列中間未知的資料
- 相等,找到
- 要找的資料較大,則對後續部分的資料做同樣的步驟
- 要找的資料較小,則對前面部分的資料做同樣的步驟
- 插值查詢 Interpolation Search
插值查詢是對二分查詢的進一步改進
如果序列不僅是一個排序好的序列,而且序列的步長大致相同,使用插值查詢會更快的找到目標。
插值查詢基於如下假設:下標之間的距離比和資料之間的距離比大致相同,即:
(目標下標-最小下標) / (最大下標 - 最小下標) ≈ (目標值 - 最小值) / (最大值 - 最小值)
因此可以算出大致的下標落點:
目標下標 ≈ (目標值 - 最小值) / (最大值 - 最小值) * (最大下標 - 最小下標) + 最小下標
這樣就可以計算出大致的下標落點,後續的比較和二分查詢一樣。
/**
* 交換陣列中指定的位置
* @param {*} arr
* @param {*} i1
* @param {*} i2
*/
function swap(arr, i1, i2) {
var temp = arr[i1]
arr[i1] = arr[i2];
arr[i2] = temp;
}
/**
* 選擇排序
* @param {*} arr
*/
function selectionSort(arr) {
for (var i = 0; i < arr.length - 1; i++) {
//搞定 i ~ arr.length-1 區間
//從該區間中找出最小值,和 第 i 位交換
var min = arr[i]; //定義一個變數,為該區間的第一個數
var index = i; //最小值所在的位置
for (var j = i + 1; j < arr.length; j++) {
if (arr[j] < min) {
min = arr[j];
index = j; //重新記錄最小值的位置
}
}
//最小值已經找出
//交換第i位和第index位
swap(arr, i, index);
}
}
/**
* 氣泡排序
* @param {*} arr
*/
function bubbleSort(arr) {
for (var i = 0; i < arr.length - 1; i++) {
//需要經過arr.length-1次的冒泡
//i:0 迴圈:0~arr.length-1-i
//i:1 迴圈:0~arr.length-1-i
//i:2 迴圈: 0~arr.length-1-i
for (var j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
swap(arr, j, j + 1);
}
}
}
}
/**
* 插入排序
* @param {*} arr
*/
function insertionSort(arr) {
for (var i = 1; i < arr.length; i++) {
if (arr[i] < arr[i - 1]) {
//將第i位的值加入到前面有序佇列的正確位置
var temp = arr[i];
for (var j = i; j >= 0; j--) {
if (j > 0 && arr[j - 1] > temp) {
arr[j] = arr[j - 1];
}
else {
arr[j] = temp;
break;
}
}
}
}
}
/**
* 快速排序
* @param {*} arr
*/
function quickSort(arr) {
/**
* 對陣列的某個區域進行一次快速排序
* @param {*} arr
* @param {*} start 區域的起始下標
* @param {*} end 區域的結束下標
*/
function _quickSort(arr, start, end) {
if (start >= end || start > arr.length - 1) return;
var low = start, high = end;
var key = arr[end]; //基準值
while (low < high) {
while (low < high && arr[low] <= key) low++;
arr[high] = arr[low];
while (low < high && arr[high] >= key) high--;
arr[low] = arr[high];
}
//low === high
arr[low] = key;
_quickSort(arr, start, low - 1);
_quickSort(arr, low + 1, end);
}
_quickSort(arr, 0, arr.length - 1);
}
var arr = [5, 3, 1, 6, 7, 4];
console.log(arr)
quickSort(arr)
console.log(arr);
複製程式碼