一、什么是算法
以下是高德纳在他的著作《计算机程序设计艺术》里对演算法的特征归纳:
输入:一个算法必须有零个或以上输入量。
输出:一个算法应有一个或以上输出量,输出量是算法计算的结果。
明确性:算法的描述必须无歧义,以保证算法的实际执行结果是精确地符合要求或期望,通常要求实际执行结果是确定的。
有限性:依据图灵的定义,一个演算法是能够被任何图灵完备系统模拟的一串运算,而图灵机只有有限个状态、有限个输入符号和有限个转移函数(指令)。而一些定义更规定演算法必须在有限个步骤内完成任务。
有效性:又称可行性。能够实现,算法中描述的操作都是可以通过已经实现的基本运算执行有限次来实现。
基于比较的排序算法:
- BUB - 冒泡排序,
- SEL - 选择排序,
- INS - 插入排序,
- MER - 归并排序 (递归实现),
- QUI - 快速排序 (递归实现),
不基于比较的排序算法:
- COU - 计数排序,
- RAD - 基数排序.
1. 冒泡排序
实现思路
- 如果元素大小关系不正确,交换这两个数(在本例中为a> b),
- 比较一对相邻元素(a,b),
- 重复步骤1和2,直到我们到达数组的末尾(最后一对是第(N-2)和(N-1)项,因为我们的数组从零开始)
- 到目前为止,最大的元素将在最后的位置。 然后我们将N减少1,并重复步骤1,直到N = 1。
JavaScript 实现代码
let bub = function bubbleSort(a) {
for (let i = 0; i < a.length - 1; i++) {
for (let j = 0; j < a.length - i - 1; j++) {
if (a[j] > a[j + 1]) {
let temp = a[j + 1]
a[j + 1] = a[j]
a[j] = temp
}
}
}
return a
}
let q = [29, 10, 14, 37, 14]
console.log(bub(q))
2. 选择排序
实现思路
n个数据的直接选择排序可经过n-1趟直接选择排序得到有序结果。
- 初始状态:无序区为R[1…n],有序区为空;
- 在 [L … N-1] 范围内找出最小项目 X 的位置,
- 用第 L 项交换X,
- 将下限 L 增加1并重复步骤1直到 L = N-2。
JavaScript 实现代码
let sel = function selectionSort(arr) {
let minIndex
let temp
for (let i = 0; i < arr.length - 1; i++) {
minIndex = i
for (let j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j
}
}
temp = arr[i]
arr[i] = arr[minIndex]
arr[minIndex] = temp
}
return arr
}
let q = [29, 10, 14, 37, 14]
console.log(sel(q))
3. 插入排序
实现思路
n个数据的直接选择排序可经过n-1趟直接选择排序得到有序结果。
- 从第一个元素开始,该元素可以认为已经被排序;
- 取出下一个元素,在已经排序的元素序列中从后向前扫描;
- 如果该元素(已排序)大于新元素,将该元素移到下一位置;
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
- 将新元素插入到该位置后;
- 重复步骤2~5。
JavaScript 实现代码
let ins = function insertionSort(arr) {
let preIndex
let current
for (let i = 1; i < arr.length; i++) {
preIndex = i - 1
current = arr[i]
while (preIndex >= 0 && arr[preIndex] > current) {
arr[preIndex + 1] = arr[preIndex]
preIndex--
}
arr[preIndex + 1] = current
}
return arr
}
let q = [29, 10, 14, 37, 14]
console.log(ins(q))
4. 归并排序
实现思路
- 把长度为n的输入序列分成两个长度为n/2的子序列;
- 对这两个子序列分别采用归并排序;
- 将两个排序好的子序列合并成一个最终的排序序列。
JavaScript 实现代码
let mer = function mergeSort(arr) {
let len = arr.length
if (len < 2) {
return arr
}
let middle = Math.floor(len / 2)
let left = arr.slice(0, middle)
let right = arr.slice(middle)
return merge(mergeSort(left), mergeSort(right))
}
function merge(left, right) {
let result = []
while (left.length && right.length) {
if (left[0] <= right[0]) {
result.push(left.shift())
} else {
result.push(right.shift())
}
}
while (left.length) {
result.push(left.shift())
}
while (right.length) {
result.push(right.shift())
}
return result
}
let q = [29, 10, 14, 37, 14]
console.log(mer(q))
5. 快速排序
实现思路
快速排序使用分治法来把一个数列为两个数列。
- 从数列中挑出一个元素,称为 “基准”(pivot);
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
- 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
JavaScript 实现代码
let qui = function quicSort(arr) {
if (arr.length <= 1) {
return arr
}
let pivotIndex = Math.floor(arr.length / 2)
let pivot = arr.splice(pivotIndex, 1)[0]
let left = []
let right = []
for (let i = 0; i < arr.length; i++) {
if (arr[i] < pivot) {
left.push(arr[i]);
} else {
right.push(arr[i]);
}
}
return quicSort(left).concat([pivot], quicSort(right));
}
let q = [29, 10, 14, 37, 14]
console.log(qui(q))