前端比较常问到排序其实也就几种,冒泡,插入,归并,希尔,快速,桶。
接下来分别概述一下它们的特点:
| 类型/特性 | 冒泡 | 插入 | 归并 | 希尔 | 快速 | 桶 |
|---|---|---|---|---|---|---|
| 时间复杂度 | O(n^2) | O(n)~O(n^2) | O(nlogn) | O(n)~O(n^2) | O(nlogn)~O(n^2) | O(n)~O(n^2) |
| 空间复杂度 | O(1) | O(1) | O(n) | O(1) | O(logn) | O(n) |
| 稳定性 | 稳定 | 稳定 | 稳定 | 不稳定 | 不稳定 | 稳定 |
冒泡排序
目前大多数程序员都会的就是冒泡排序,简单明了,两两比对,大的放后面,小的放前面,第一次循环之后,最大的元素就跑到数组最后面去了。
function bubbleSort (nums) {
const length = nums.length;
for (let i = 0;i < length;++i) {
for (let j = 0;j < length - 1 - i;++j) {
if (nums[j] > nums[j+1]) [nums[j+1], nums[j]] = [nums[j], nums[j+1]]
}
}
}
由于会进行两次遍历所以时间复杂度依旧是O(n^2)
插入排序
这种排序也是进行两次遍历,不过它会与前面的进行比较,每次比较将数插入到对应的位置
function insertSort (nums) {
const length = nums.length;
for (let i = 1;i < length;++i) {
let curIndex = i;
while (curIndex >= 0 && nums[--curIndex] > nums[i]) continue;
nums.splice(curIndex + 1, 0, nums.splice(i, 1)[0])
}
}
归并排序
它是把数组进行拆分,分别进行排序,在将排完序的数组进行合并
function mergeSort (nums) {
const length = nums.length;
if (length < 2) return nums;
const mid = ~~(nums.length / 2);
const left = mergeSort(nums.slice(0, mid)),right = mergeSort(nums.slice(mid));
return merge(left, right);
}
function merge (left, right) {
const result = [];
while (left.length && right.length) {
if (left[0] > right[0]) {
result.push(right.shift());
} else {
result.push(left.shift());
}
}
if (left.length) {
result.push(...left);
}
if (right.length) {
result.push(...right);
}
return result;
}
希尔排序
它是插入排序的一种优化,设置了一个间隔序列,提高速度
function shellSort (nums) {
const length = nums.length;
let temp, gap = 1;
while (gap < length / 3) {
gap = gap * 3 + 1;
}
for (;gap > 0;gap = ~~(gap / 3)) {
for (let i = gap;i < length; ++i) {
temp = nums[i];
for (let j = i - gap;j >= 0 && nums[j] > temp; j-=gap) {
nums[j + gap] = nums[j];
}
nums[j + gap] = temp;
}
}
return nums;
}
快速排序
在顺序比较乱的时候,快排的执行效率比较高,它跟归并都是将数组拆分成再进行合并,不过它的常数因子更小,也就更快
function quickSort (nums) {
if (nums.length < 2) {
return nums;
}
const mid = ~~(nums.length / 2),
num = nums.splice(mid, 1)[0],
left = [],
right = []
for (let i = 0,length = nums.length;i < length; ++i) {
if (nums[i] < num) {
left.push(nums[i]);
} else {
right.push(nums[i]);
}
}
return quickSort(left).concat(num, quickSort(right));
}
桶排序
它是通过映射进行快速排序的,所以映射越多,内存消耗越大。
function bucketSort (nums, bucketSize) {
if (nums.length) {
return nums;
}
let i;
let minValue = nums[0]; // 输入最小值
let maxValue = nums[0]; // 输入最大值
for (i = 1;i < nums.length; ++i) {
if (nums[i] < minValue) {
minValue = nums[i]
} else if (nums[i] > maxValue) {
maxValue = nums[i]
}
}
const DEFAULT_BUCKET_SIZE = 5; // 设置桶的默认值为5
bucketSize = bucketSize || DEFAULT_BUCKET_SIZE;
const bucketCount = ~~((maxValue - minValue) / bucketSize);
const buckets = Array.from({ length: bucketCount }, () => []);
// 将数据分配给桶进行映射
for (i = 0;i < nums.length; ++i) {
buckets[~~((nums[i] - minValue) / bucketSize)].push(nums[i]);
}
nums.length = 0;
for (i = 0;i < buckets.length; ++i) {
insertSort(buckets[i]);
for (let j = 0;j < buckets[i].length; ++j) {
nums.push(buckets[i][j]);
}
}
return nums;
}