种类
- 冒泡排序
- 计数排序
- 插入排序
- 选择排序
- 归并排序
- 快速排序
冒泡排序 时间复杂度O(n*n)
思路
-
从头到尾依次比较前者跟后者大小,若前者比后者大,两者互换位置;
-
针对n个元素重复以上步骤,每次循环排除当前最后一个。
-
重复步骤1、2,排序完成。
代码实现
const sort = function(arr){
const len = arr.length;
for (let i = 0; i < len; i++) {
for (let j = 0; j < len; j++) {
if(arr[j] > arr[j+1]){
[arr[j], arr[j+1]] = [arr[j+1], arr[j]]
}
}
}
return arr;
}
sort([2,1,3,5,9,4,0]); // [0, 1, 2, 3, 4, 5, 9]
计数排序 时间复杂度:O(n+k)
思路
- 计算出差值diff,最小值小于0,加上本身add
- 创建统计数组并统计对应元素个数
- 遍历统计数组,输出到结果数组
代码实现
const sort = function(arr){
let len = arr.length,
min = arr[0],
max = arr[0];
// 求最大/小值
for (let i = 1; i < len; i++) {
max = Math.max(arr[i], max)
min = Math.min(arr[i], min)
}
// 最小值小于0时,应加上绝对值,以便获得实际最大与最小值的实际差额(此差额以长度表示,便于创建新数组)
let add = (min < 0 ? -min : 0);
let diff = max - min + add + 1;
let newArr = new Array(diff).fill(0);
// 存储对应值出现的次数
for (let i = 0; i < len; i++) {
const inx = arr[i] - min + add;
newArr[inx] += 1;
}
return newArr.reduce((_arr, v, i)=>{
const rArr = new Array(v).fill(i);
v && ( _arr = _arr.concat(rArr));
return _arr;
}, []);
}
sort([0,2,1,5,8,7,6,3,4,0]); // [0, 0, 1, 2, 3, 4, 5, 6, 7, 8]
插入排序 时间复杂度: O(n*n)
思路
-
从第一个元素开始,该元素可以认为已经被排序;
-
取出下一个元素,在已经排序的元素序列中从后向前扫描;
-
如果该元素(已排序)大于当前索引元素,将该元素移到下一位置;
-
重复步骤3,结束后将筛选的最前面元素替换成当前索引元素;
-
重复步骤2~4。
const sort = function(arr){
let len = arr.length;
for (let i = 0; i < len; i++) {
let pInx = i - 1,
cur = arr[i];
while (pInx>=0&&cur<arr[pInx]) {
arr[pInx+1] = arr[pInx]
pInx--;
}
arr[pInx+1] = cur;
}
return arr;
}
sort([0,2,1,5,8,7,6,3,4,0]); // [0, 0, 1, 2, 3, 4, 5, 6, 7, 8]
选择排序 时间复杂度O(n*n)
思路
-
循环数组,记录当前索引
-
将该索引元素与之后的元素进行判断,若筛选到小于该数时,记录索引,结束循环后交换位置; (每趟仅记录一个最小值)
const sort = function(arr){
let inx, len = arr.length;
for (let i = 0; i < len; i++) {
inx = i;
for (let j = i+1; j < len; j++) {
if(arr[j] < arr[inx]){
inx = j;
}
}
// 有更小值时执行
if(inx !== i){
[arr[inx], arr[i]] = [arr[i], arr[inx]]
}
}
return arr;
}
sort([0,2,1,5,8,7,6,3,4,0]); // [0, 0, 1, 2, 3, 4, 5, 6, 7, 8]
归并排序 时间复杂度:O(nlogn)
思路
-
将数组拆分成A、B两份,直至拆成单个元素;
-
从单元素数组开始对拆分数组进行排序处理;
-
重复步骤2;
function sort(arr){
const len = arr.length;
if(len < 2){
return arr;
}
const inx = Math.floor(len / 2);
const leftArr = arr.slice(0,inx)
const rightArr = arr.slice(inx);
return menber(sort(leftArr), sort(rightArr))
}
function menber(left, right){
let _arr = [];
while (left.length && right.length) {
_arr.push(left[0] > right[0] ? right.shift() : left.shift())
}
return _arr.concat(left,right);
}
sort([0,2,1,5,8,7,6,3,4,0]); // [0, 0, 1, 2, 3, 4, 5, 6, 7, 8]
快速排序 时间复杂度:O(nlogn)
思路
-
选择数组中间数作为基数
-
准备两个容器,遍历数组与基数比对,较小的放左边容器,较大的放右边容器;
-
递归处理,将处理后的数据与基数按大小合并成一个数组。
function sort(arr){
let len = arr.length;
if (len <= 1) return arr;
let index = Math.floor(len / 2)
let mean = arr.splice(index, 1)[0],
left = [],
right = [];
for (let i = 0; i < len; i++) {
mean > arr[i] ? left.push(arr[i]) : right.push(arr[i]);
}
return sort(left).concat([mean], sort(right));
}
sort([0,2,1,5,8,7,6,3,4,0]); // [0, 0, 1, 2, 3, 4, 5, 6, 7, 8]