排序总结
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-32VQSgpU-1665396147681)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6c94713cc9cd450c9608dc4da4672b75~tplv-k3u1fbpfcp-watermark.image?)]
1、 冒泡排序
Bubble Sort 是一种交换排序,它的基本思想是:两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。
var arr = [1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
var crr = arr.sort(() => Math.random() - 0.5);
for (var i = 0; i < crr.length; i++) {
for (var j = i; j < crr.length; j++) {
if (crr[i] > crr[j]) {
[crr[i], crr[j]] = [crr[j], crr[i]];
}
}
}
2、 快速排序
快速排序(Quicksort)步骤
- 首先设定一个分界值,通过该分界值将数组分成左右两部分。
- 将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于分界值,而右边部分中各元素都大于或等于分界值。
- 左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理
- 重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。
- 时间复杂度:O(nlogn),最优为O(nlogn),最坏为O(n²),平均为O(nlogn)。
- 空间复杂度:O(logn)
var sortArray = function (nums) {
let len = nums.length
if (len === 1) {
return nums
}
quickSort(nums, 0, len - 1)
function quickSort(nums, left, right) {
if (left < right) {
let pivot = partition(nums, left, right)
quickSort(nums, left, pivot - 1)
quickSort(nums, pivot + 1, right)
}
}
function partition(nums, left, right) {
let i = left, j = right + 1
let pivot = nums[left]
while (true) {
while (nums[++i] < pivot) {
if (i === right) {
break
}
}
while (pivot < nums[--j]) {
if (j === left) {
break
}
}
if (i >= j) {
break
}
[nums[i], nums[j]] = [nums[j], nums[i]]
}
if(left != j){
[nums[left], nums[j]] = [nums[j], nums[left]]
}
return j
}
return nums
};
console.log(sortArray([5,3,1,4,2,7,6]))
在代码中,分别在这几个位置打上断点,可以理解代码走的流程,如下图所示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EVcp9kFL-1665396147682)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0f4b17f4ee5d4d6fbe507ae84892b078~tplv-k3u1fbpfcp-watermark.image?)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YUbSWdbj-1665396147682)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/fa8d93008bc743c1bfd8c64f43314598~tplv-k3u1fbpfcp-watermark.image?)]
3、选择排序
选择排序(Selection sort)工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。
时间复杂度:O(n²),最优为O(n²),最坏为O(n²),平均为O(n²)。
空间复杂度:O(1)
var sortArray = function (nums) {
let len = nums.length;
if (len === 1) {
return nums;
}
for (let i = 0; i < len; i++) {
let minIndex = i
for (let j = i + 1; j <len; j++) {
if (nums[j] < nums[minIndex]) {
minIndex = j
}
}
if (minIndex !== i) {
[nums[minIndex], nums[i]] = [nums[i], nums[minIndex]]
}
}
return nums
};
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yx7oRIB5-1665396147683)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1e3515e87eea40028e2e9ffac3cad0b1~tplv-k3u1fbpfcp-watermark.image?)]
4、插入排序
插入排序,一般也被称为直接插入排序。对于少量元素的排序,它是一个有效的算法 。插入排序的基本思想是在一个已经排好序的有序表中,插入一个新的值,重新排序冒泡一次,直到被插入的值找到的合适的位置结束,进行下一次循环
时间复杂度:O(n²),最优为O(n),最坏为O(n²),平均为O(n²)。
空间复杂度:O(1)
var sortArray = function (nums) {
let len = nums.length;
if (len === 1) {
return nums;
}
for (let i = 1; i < nums.length; i++) {
for (let j = i; j > 0 && (nums[j] < nums[j - 1]); j--) {
[nums[j], nums[j - 1]] = [nums[j - 1], nums[j]]
}
}
return nums
};
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DXDr29Zs-1665396147683)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/01f7d5bf446e4b5288b560b5b3639291~tplv-k3u1fbpfcp-watermark.image?)]
5、 希尔排序
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止。
代码实现在这里
var sortArray = function(nums) {
var h = 1
var len = nums.length
while(h < len/2){
h = 2*h + 1
}
while(h>=1){
for(var i = h;i<len;i++){
for(var j = i;j>= h && nums[j] < nums[j - h] ; j = j - h){
[nums[j],nums[j-h]] = [nums[j-h],nums[j]]
}
}
h = h >> 1
}
return nums
};
调试代码 加下面
var brr = [];
for (var i = 0; i < 10; i++) {
brr.push(i);
}
var arr = brr.sort(function () {
return Math.random() - 0.5;
});
console.log(arr);
console.log(sortArray([0, 1, 9, 7, 6, 8, 2, 3, 4, 5]));
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zr2EGcpU-1665396147683)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/92dbfa7115454122a2e1257b5d4f2a44~tplv-k3u1fbpfcp-watermark.image?)]
6、归并排序
归并排序是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
代码实现
var sortArray = function (nums) {
function merge(left, right) {
const res = []
while (left.length && right.length) {
if (left[0] < right[0]) {
res.push(left.shift())
} else {
res.push(right.shift())
}
}
return res.concat(left).concat(right)
}
function mergeSort(nums) {
const len = nums.length
if (len === 1) {
return nums;
}
const mid = len >> 1
const left = nums.slice(0, mid)
const right = nums.slice(mid)
return merge(mergeSort(left), mergeSort(right))
}
return mergeSort(nums)
};
调试代码
var brr = [];
for (var i = 0; i < 10; i++) {
brr.push(i);
}
var arr = brr.sort(function () {
return Math.random() - 0.5;
});
console.log(arr);
// console.log(sortArray(arr));
console.log(sortArray([0, 1, 9, 7, 6, 8, 2, 5, 4, 3]));
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kS28wx3o-1665396147684)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/77dcedc776be4523956b30ef9eaf9ea5~tplv-k3u1fbpfcp-watermark.image?)]
7、 桶排序
var sortArray = function(nums) {
var len = nums.length;
if(len <=1){
return nums
}
var max = nums[0]
var min = nums[0]
for(var i = 1;i<len;i++){
if(nums[i]>max){
max = nums[i]
}
if(nums[i]<min){
min = nums[i]
}
}
var arr = []
for(var i =0;i<len;i++){
var j = Math.floor((nums[i] - min) / 3) >> 1
if(!arr[j]){
arr[j] = []
}
arr[j].push(nums[i])
}
var arrNums = Math.floor((max - min ) / 3) + 1
nums = []
for(var j =0;j<arrNums;j++){
if(arr[j]){
insertSort(arr[j])
nums = nums.concat(arr[j])
}
}
return nums
function insertSort(brr){
var len = brr.length;
for(var i=1;i<len;i++){
for(var j = i;j>0 && brr[j] < brr[j - 1];j--){
[brr[j],brr[j-1]] = [brr[j-1],brr[j]]
}
}
return brr
}
};
8、 基数排序
- Radix Sort,非比较型整数排序,将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。
- 非比较排序因为不涉及比较,其基本操作的代价较小,所以在一定情况下,基数排序一般要快过基于比较的排序,比如快速排序。
代码实现
var sortArray = function (nums) {
let len = nums.length;
if (len < 2) {
return nums;
}
// nums的最大值
let max = Math.max.apply(null, nums);
// max的位数,如131就是3位
let maxDigit = 1;
while ((max = Math.floor(max / 10))) {
maxDigit++;
}
var count = [];
let mod = 10;
let dev = 1;
for (let i = 0; i < maxDigit; i++) {
count = [];
for (let j = 0; j < len; j++) {
var item = nums[j]
var bucket = Math.floor((nums[j] % mod) / dev);
console.log(item);
console.log(bucket);
if (count[bucket]) {
count[bucket].push(nums[j]);
} else {
count[bucket] = [nums[j]];
}
}
console.log(count);
let pos = 0;
for (let j = 0; j < count.length; j++) {
let value = null;
if (count[j]) {
while ((value = count[j].shift()) != null) {
nums[pos++] = value;
}
}
}
dev *= 10;
mod *= 10;
}
return nums;
};
var brr = [];
for (var i = 0; i < 700; i = i * 2 + 1) {
brr.push(i);
}
var arr = brr.sort(function () {
return Math.random() - 0.5;
});
// console.log(arr);
// console.log(sortArray(arr));
console.log(sortArray([21, 7, 19, 10, 1, 23, 16, 12, 8, 5]));
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4Gap6hwn-1665396147684)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ff64cf7558ee420c9016554074b91dbb~tplv-k3u1fbpfcp-watermark.image?)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZBbdzb4z-1665396147684)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d5c03919df004bae95c1e46b98c53620~tplv-k3u1fbpfcp-watermark.image?)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BmMRDP6M-1665396147684)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/efaaf10301f349dfbbf18a66c2f19a42~tplv-k3u1fbpfcp-watermark.image?)]
9、 堆排序
var sortArray = function (nums, size=3) {
let len = nums.length
if(len<2) {
return nums
}
const half = len >> 1
let i = half - 1
while(i>=0) {
max_heapify(nums,i ,len)
i--
}
for(let i = len-1; i>0; i--) {
swap(nums, 0, i)
max_heapify(nums, 0, i)
}
return nums
};
function max_heapify(arr, start, end) {
let parentIndex = start, sonIndex = parentIndex*2 + 1
if(sonIndex>=end) {
return
}
// 左子节点<右子节点
if(sonIndex+1<end && arr[sonIndex]<arr[sonIndex+1]) {
sonIndex++
}
if(arr[parentIndex]<arr[sonIndex]) {
swap(arr, parentIndex, sonIndex)
max_heapify(arr, sonIndex, end)
}
}
function swap(a, i,j) {
[ a[i], a[j] ] = [ a[j], a[i] ]
}
10、 计数排序
- 计数排序不是一个比较的排序算法,元素从未排序状态变为已排序状态的过程,是由额外空间的辅助和元素本身的值决定的。它的优势在于对一定范围内的整数排序时,它的复杂度为Ο(n+k)(其中k是整数的范围),快于任何比较排序算法。当然这是一种牺牲空间换取时间的做法,而且当O(k) > O(nlogn)的时候其效率反而不如基于比较的排序,因为基于比较的排序的时间复杂度在理论上的下限是O(nlogn)。
- 由于用来计数的数组count的长度取决于待排序数组中数据的范围(等于待排序数组的最大值与最小值的差加上1),这使得计数排序对于数据范围很大的数组,需要大量时间和内存。例如:计数排序是用来排序0到100之间的数字的最好的算法,但是它不适合按字母顺序排序人名。
代码实现
var sortArray = function (nums) {
let len = nums.length
if(len<2) {
return nums
}
const count = []
for(let i=0; i<len; i++) {
const j = nums[i]
if(count[j]) {
count[j] ++
} else {
count[j] = 1
}
}
const res = []
for(let j=0; j<count.length; j++) {
if(count[j]) {
while(count[j]>0) {
res.push(j)
count[j] --
}
}
}
return res
};
调试代码
var brr = [];
for (var i = 0; i < 700; i = i*2 + 1) {
brr.push(i);
}
var arr = brr.sort(function () {
return Math.random() - 0.5;
});
// console.log(arr);
// console.log(sortArray(arr));
console.log(sortArray([21, 7, 19, 10, 1, 23, 16, 12, 8, 5,5]));
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-irL3gQ2l-1665396147685)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/04ca096be60d4f23949cb6118f451edd~tplv-k3u1fbpfcp-watermark.image?)]