JavaScript实现常见排序算法:冒泡,插入,选择,归并,快速,堆排序
Posted cwxblog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript实现常见排序算法:冒泡,插入,选择,归并,快速,堆排序相关的知识,希望对你有一定的参考价值。
1.冒泡排序
转自百度百科:
冒泡排序,这个算法的名字由来是因为越大的元素会经由交换慢慢“浮”到数列的顶端,故名“冒泡排序”。
冒泡排序算法的运作如下:(从后往前)
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
以下过程动图摘自依韵的博客:
/**
* 冒泡排序:每个元素跟剩下的元素相比,直到冒到剩下的最大
* 时间复杂度O(n^2);
* 空间复杂度 O(1);
* 是否稳定:
* @param array arr
* @returns
*/
const bubbleSort = function(arr)
let arrLen = arr.length;
for(let i = 0; i < arrLen; i++)
for(let j = 0 ; j < arrLen - i; j++)
// 相邻元素交换
if (arr[j] > arr[j+1])
// swap(arr[j], arr[j+1])
let temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
return arr;
console.time('bubble')
console.log(bubbleSort([3,44,38,5,47,15,36,26,27,2,46,4,19,50,48]))
console.timeEnd('bubble')
2. 选择排序
/*
* @description: 选择排序,不断在剩余元素中选择最小/最大的元素
* 时间复杂度O(n^2);
* 空间复杂度 O(1);
* 是否稳定:
*/
const selectSort = function(arr)
let len = arr.length;
for(let i=0; i<len; i++)
let minNum = arr[i]
for(let j=i; j<len; j++)
if(minNum > arr[j])
// swap(minNum, arr[j])
let temp = minNum;
minNum = arr[j];
arr[j] = temp;
arr[i] = minNum
return arr;
console.log(selectSort([2,5,34,6,3]))
3. 插入排序
/*
* @description: 每个元素插入前面已经拍好序的元素中合适的位置,其他元素依次移动; 适合基本有序队列的排序
* 时间复杂度O(n^2);
* 空间复杂度 O(1);
* 是否稳定:
*/
const insertSort = function(arr)
const n = arr.length;
for (let i=0; i<n; i++)
for (let j=i; j>0; j--)
if (arr[j] < arr[j-1])
// swap(arr[j], arr[j-1])
[arr[j], arr[j-1]] = [arr[j-1], arr[j]]
return arr;
console.time("time")
console.log(insertSort([3,44,38,5,47,15,36,26,27,2,46,4,19,50,48]))
console.timeEnd('time');
4. 快速排序
/**
* 快速排序的主要思想是通过划分将待排序的序列分成前后两部分,其中前一部分的数据都比后一部分的数据要小,然后再递归调用函数对两部分的序列分别进行快速排序,以此使整个序列达到有序。
* 快速排序: 快速排序又是一种分而治之思想在排序算法上的典型应用。本质上来看,快速排序应该算是在冒泡排序基础上的递归分治法。
* 1. 从数列中挑出一个元素,称为 "基准"(pivot);
* 2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
* 3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;
* 时间复杂度:O(nlogn)
* 空间复杂度:O(h)
* 是否稳定:不稳定
* @param * arr
*/
function quickSort(arr)
QSort(arr, 0, arr.length-1)
/**
* 快速排序函数
* @param * arr 待排序数组
* @param Number low 最小下标值
* @param Number high 最大下标值
*/
function QSort(arr, low, high)
let pivot = 0;
if (low < high)
// 获取基准值的下标
pivot = Partition(arr, low, high);
QSort(arr, low, pivot - 1);
QSort(arr, pivot + 1, high);
/**
* 切分函数:
* @param * arr
* @param Number low
* @param Number high
* @returns 基准值下标
*/
function Partition(arr, low, high)
// 子数组的第一个值作为基准值,存在性能陷阱(取到最小值,或者最大值),理想情况是取到中间的数值
// let pivotkey = arr[low];
// or三数取中法获得基准点(效率好一点)
let m = low + (high - low) / 2;
if (arr[low] > arr[high])
swap(arr, low, high);
if (arr[m] > arr[high])
swap(arr, m, high)
if (arr[low] > arr[m])
swap(arr, low, m)
let pivotkey = arr[low];
// 大于基准点的放在右边,小于基准点的放在左边
while(low < high)
while(low < high && arr[high] >= pivotkey)
high--;
swap(arr, low, high)
while(low < high && arr[low] <= pivotkey)
low++
swap(arr, low, high)
return low;
/**
* 交换函数
*/
function swap(arr, a, b)
let temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
let arr = [3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.time("time")
quickSort(arr);
console.log(arr);
console.timeEnd('time');
5. 堆排序
/**
* 堆排序
* 实际上是选择排序的一种,我们可以看到堆的结构是一个完全二叉树,采用一维数组存储
* 以大顶堆为例
* 性质:这里用到了完全二叉树性质,对于一个n个节点的完全二叉树的节点按层序变化,对任一节点i (1<=i<=n)。
* 1. 如果i = 1, 则节点 i 是二叉树的根,无双亲;如果 i>1 ,其双亲节点是Math.floor(i/2),向下取整。
* 2. 如果 2i > n, 则节点无左孩子; 否则左孩子是节点 2i。
* 3. 如果 2i+1 > n, 则节点无右孩子,否则右孩子是节点 2i+1。
* 算法中之所以为Math.floor(n/2) - 1, 因其存储下标从0开始,
*/
function heapSort(arr)
/**
* 建堆
*/
const n = arr.length;
// 索引从0开始,最后一个非叶子节点Math.floor(n/2) - 1
for(let i = Math.floor(n/2) - 1; i >= 0; i--)
adjustHeap(arr, i, n);
// 堆排,每次选择堆顶元素 arr[0] (剩余最大元素),与末尾元素 arr[i] 进行交换
for( let i = n - 1; i > 0; i--)
swap(arr, 0, i);
adjustHeap(arr, 0, i);
return arr;
/**
* 堆调整
* @param 待排序数组 arr
* @param 当前起始节点 i
* @param 堆的长度 n
*/
function adjustHeap(arr, i, n)
let leftChild = 2 * i + 1;
let rightChild = 2 * i + 2;
// 假设初始节点最大
let largeNode = i;
// 左节点存在 && 左节点大于初始节点
if ( leftChild < n && arr[leftChild] > arr[largeNode])
largeNode = leftChild;
// 右节点存在 && 右节点大于初始节点/左节点
if (rightChild < n && arr[rightChild] > arr[largeNode])
largeNode = rightChild;
if (largeNode !== i)
// 将最大的节点和初始节点调整位置
swap(arr, i, largeNode);
// 再往下继续调整
adjustHeap(arr, largeNode, n)
/**
* 交换元素
* @param arr
* @param 交换元素下标 a
* @param 交换元素下标 b
*/
function swap(arr, a, b)
let temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
console.log(heapSort([90,70,80,60,10,40,50,30,20]))
以上是关于JavaScript实现常见排序算法:冒泡,插入,选择,归并,快速,堆排序的主要内容,如果未能解决你的问题,请参考以下文章