排序和查找 {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);