排序算法 | 平均情况 | 最好情况 | 最坏情况 | 辅助空间 | 稳定性 |
---|---|---|---|---|---|
冒泡排序 | O(n^2) | O(n) | O(n^2) | O(1) | 稳定 |
简单选择排序 | O(n^2) | O(n^2) | O(n^2) | O(1) | 稳定 |
直接插入排序 | O(n^2) | O(n) | O(n^2) | O(1) | 稳定 |
希尔排序 | O(nlogn)~O(n^2) | O(n^1.3) | O(n^2) | O(1) | 不稳定 |
堆排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(1) | 不稳定 |
归并排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | 稳定 |
快速排序 | O(nlogn) | O(nlogn) | O(n^2) | O(nlogn)~O(n) | 不稳定 |
简单算法:冒泡、简单选择、直接插入
改进算法:希尔、堆、归并、快速
后三种改进算法比希尔算法效率高,但最好的情况下,冒泡和直接插入最有效,因此如果数组基本有序,则需要考虑简单算法
1. 冒泡排序
一、分析
- 冒泡arr.length-1趟;
- 第i趟,比较arr.length-i-1次,两两比较,反序则交换位置。
改进:为了避免已经有序的情况下进行无意义的两两比较,用flag标志上一趟是否有交换,没有交换则已经是有序数组,退出循环。
二、代码
function bubbleSort(arr){
var flag=true;
for(let i=0;i<arr.length&&flag;i++){
flag=false;
for(let j=0;j<arr.length-i-1;j++){
if(arr[j]>arr[j+1]){
[arr[j],arr[j+1]]=[arr[j+1],arr[j]];
flag=true;
}
}
}
return arr;
}
2. 简单选择排序
一、分析
- 循环arr.length-1次,每一次的当前项与其之后的项作比较,找出其中最小的那个,与当前项交换。
二、代码
function selectSort(arr){
var min=0;
for(let i=0;i<arr.length-1;i++){
for(let j=i+1;j<arr.length;j++){
if(arr[j]<arr[min]){
min=j;
}
}
if(i!=min){
[arr[i],arr[min]]=[arr[min],arr[i]];
}
}
return arr;
}
3. 直接插入排序
一、分析
- 从数组的第二项开始,循环arr.length-1次;
- 将当前项的值赋值给临时变量:(留出一个“坑”)为了前面大于当前项的项能够后移;
- 当前项与其前面的项比较,如果大于当前项后移,直到找到小于当前项的那个,将当前项插入其后;
- 如果前面没有小于当前项的,前面项全部后移以为,当前项就插入位置0处。
二、代码
function insertSort(arr){
for(let i=1;i<arr.length;i++){
let temp=arr[i];
let j=i-1;
while(j>=0&&arr[j]>temp){
arr[j+1]=arr[j];
j--;
}
arr[j+1]=temp;
}
return arr;
}
4. 希尔排序
是一种改进版的插入排序,“缩小增量排序”。
一、分析
- 通过增量将待排序列分割成若干个子序列,每个子序列进行插入排序;
- 缩小增量,重复步骤1,直到增量不大于0;
- ps:增量等于1时,进行了一次全排的直接插入排序。这样做的目的是因为,直接插入排序在序列基本有序时效率最高。
二、代码
function shellSort(arr){
for(let increment=Math.floor(arr.length/2);increment>0;increment=Math.floor(increment/2)){
for(let i=increment;i<arr.length;i++){
let temp=arr[i];
let j=i-increment;
while(j>=0&&arr[j]>temp){
arr[j+increment]=arr[j];
j-=increment;
}
arr[j+increment]=temp;
}
}
return arr;
}
5. 堆排序
一、分析
- 将待排序列构造成一个大顶堆(位置0处,也就是堆顶,为最大数);
- 将arr[0]与arr[arr.length-1]进行交换,此时数组尾为最大值;
- 调整0~arr.length-2成一个大顶堆,继续2,直到全部排完。
二、代码
function heapSort(arr){
//1. 构造大顶堆
//2. 顶值最大,交换到最末尾
//3. 调整大顶堆
var len=arr.length;
for(let i=Math.floor(len/2)-1;i>=0;i--){
heapAdjust(arr,i,len);
}
for(let i=arr.length-1;i>0;i--){
[arr[0],arr[i]]=[arr[i],arr[0]];
heapAdjust(arr,0,i);
}
return arr;
}
function heapAdjust(arr,pos,len){
var root=pos;
for(let i=2*pos+1;i<len;i=2*i+1){
if(i+1<len&&arr[i]<arr[i+1]){
i++;
}
if(arr[temp]<arr[i]){
[arr[temp],arr[i]]=[arr[i],arr[temp]];
}
root=i;
}
// return arr;
}
6. 归并排序
一、分析
- 将两个有序数组合成一个有序数组:归并。
- 将一个数组分割成长度为1的数组,就可以当做它是一个有序数组,两两合并,就成了一个长度为2的有序数组,再两两合并,直到排序完成。
二、代码
function mergeSort(arr){
if(arr.length<=1){return arr};
let mid=Math.floor(arr.length/2);
let left=arr.slice(0,mid);
let right=arr.slice(mid);
// console.log(left+"+"+right);
return merge(mergeSort(left),mergeSort(right));
}
function merge(left,right){
var result=[];
while(left.length>0&&right.length>0){
if(left[0]<right[0]){
result.push(left.shift());
}
else{
result.push(right.shift());
}
}
return result.concat(left,right);
}
7. 快速排序
一、分析
- 找基准
- 小于基准的放左边,大于基准的放右边;
- 递归基准左、右无序序列找基准;
- 直到输入数组长度为1,跳出递归。
二、代码
function qSort1(arr){
if(arr.length<=1){return arr;}
let pivot=arr[0];
let left=[];let right=[];
for(let i=1;i<arr.length;i++){
if(arr[i]<pivot){
left.push(arr[i]);
}
else{
right.push(arr[i]);
}
}
return qSort1(left).concat(pivot,qSort1(right));
}
function qSort2(arr,low,high){
if(low<high){
var pivot=partition(arr,low,high);
qSort2(arr,pivot+1,high);
qSort2(arr,low,pivot-1);
}
// return arr;
}
function partition(arr,low,high){
var pivot=arr[low];
while(low<high){
while(low<high&&pivot<=arr[high]){
high--;
}
[arr[low],arr[high]]=[arr[high],arr[low]];
while(low<high&&pivot>=arr[low]){
low++
}
[arr[low],arr[high]]=[arr[high],arr[low]];
}
return low;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。