假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。
稳定排序有:插入排序、冒泡排序、归并排序
不稳定排序:希尔排序、快速排序、选择排序、堆排序
let arr = [8657, 2, 3, 4, 2, 3, 23, 4, 234, 5, 456, 456, 23]
冒泡排序(O(n^2)
)
function sort(arr) {
for (let i = 0, len = arr.length; i < len; i++) {
for (let j = i + 1; j < len; j++) {
if (arr[i] > arr[j]) {
let temp = arr[j]
arr[j] = arr[i]
arr[i] = temp
}
}
}
return arr
}
arr = sort(arr)
插入排序(O(n^2)
)
function sort(arr) {
for (let i = 1, len = arr.length; i < len; i++) {
for (let j = i; j >= 0 && arr[j] < arr[j - 1]; j--) {
let temp = arr[j]
arr[j] = arr[j - 1]
arr[j - 1] = temp
}
}
return arr
}
arr = sort(arr)
希尔排序(插入排序的改进版)
// 将表分为几段长度,分别进行排序,然后进行总的排序
function sort(arr) {
let [len, i, j, temp] = [arr.length]
do {
len = Math.floor(len / 3 + 1);
for (i = len; i < arr.length; i++) {
if (arr[i] < arr[i - len]) {
temp = arr[i]; // 先将小的数值存储
// 遍历前面的数值,将比找到的这个小的值大的值往后移
for (j = i - len; j >= 0 && temp < arr[j]; j -= len) {
arr[j + len] = arr[j]; // 不断移动,找到这个 temp 应该插入的位置
}
arr[j + len] = temp; // 插入该位置
}
}
}
while (len > 1)
return arr
}
快速排序(O(n log n)
)
- 选基准:中间值
- 划分区:跟基准比较
- 递归
function sort(arr) {
if (arr.length <= 1) return arr
let pivotIndex = Math.floor(arr.length / 2)
let pivot = arr.splice(pivotIndex, 1)[0]
let left = [], right = []
for (let i = 0, len = arr.length; i < len; i++) {
if (arr[i] < pivot) {
left.push(arr[i])
} else {
right.push(arr[i])
}
}
return sort(left).concat([pivot], sort(right))
}
arr = sort(arr)
归并排序(O(n log n)
)
先分后治
function sort(arr) {
if (arr.length <= 1) return arr
let mid = Math.floor(arr.length / 2)
let left = arr.slice(0, mid), right = arr.slice(mid) // 分
let marge = (left, right) => { // 用来融合两个有序数组(治)
let minArr = []
// 将值较小的 push 进入 minArr,并 shift 掉比较后的第一个元素
while (left.length && right.length)
left[0] < right[0] ? minArr.push(left.shift()) : minArr.push(right.shift());
return [...minArr, ...left, ...right]
}
return marge(arguments.callee(left), arguments.callee(right))
}
arr = sort(arr)