冒泡排序
思路:
一从小到大排序为例,每次从前往后挨个找出前一项比后一项大的情况,并交换两个值,往往只交换一轮是不够的,每轮交换只能把最大的值放在最后,因此还需要一个变量来控制交换轮次,并且每轮只需要交换到新的最大值的那个位置,而不需走到最后,因为上一轮已经把最大值排好了。
最坏情况:每次比较之后都需要交换位置,此时时间复杂度为O(n²)
最好情况:待排序的数列有序,只需要一轮排序并且不用交换,时间复杂度为O(n)
function bubbleSort(arr){
const len=arr.length;
for(let i=0;i<len-1;i++){
for(let j=0;j<len-i-1;j++){
// 相邻元素两两对比
if(arr[j]>arr[j+1]){
// 元素交换
let temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
return arr;
}
优化:
上面冒泡过程中存在的问题是,到后面的几个轮数中即使没有数值发生交换,也会从头到尾比较大小。因此我们可以加入标志性的变量来记录该轮次有没有发生数据交换,如果没有就说明都排好的,就不需要再遍历,而是立即结束排序,避免不必要的比较过程。那么该如何记录呢
function bubbleSort1(arr){
const i=arr.length-1;//初始时,最后位置保持不变
while(i>0){
let pos = 0;//每趟开始时,重置,表示当前轮无记录交换
for(let j = 0; j < i; j++){
if(arr[j] > arr[j+1]){
let tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
//每交换一次就更新pos,记录最后交换j的位置
pos = j;
}
}
//下一趟排序只需要交换到上一次的pos位置
i = pos;
}
// 如果i=0说明没有要交换的了,直接退出
return arr;
}
对于同样大小的元素来说,相对位置是不会改变的,因此, 冒泡排序是稳定的
双重嵌套循环相比其它排序算法是相对较高的时间复杂度,一般情况不推荐使用
选择排序
思路:
以从小到大排序为例,仍然是遍历n-1轮,每轮从未排序的部分选择最小的数,与最前面的数交换,这样下一个数就排序完了,再从剩下未排序的数里面找最小数
function selectionSort(arr){
const len=arr.length;
var minIndex,temp;
for(let i=0;i<len-1;i++){
minIndex=i;
for(let j=i+1;j<len;j++){
// 遍历未排序的数,寻找最小的数
if(arr[j]<arr[minIndex]{
// 只保存最小数的索引
minIndex=j;
}
}
temp=arr[i];
arr[i]=arr[minIndex];
arr[minIndex]=temp;
}
return arr;
}
第一次内循环比较N - 1
次,然后是N-2
次,N-3
次,……,最后一次内循环比较1次 共比较的次数是 (N - 1) + (N - 2) + ... + 1
,求等差数列和,得 (N - 1 + 1)* N / 2 = N^2 / 2
,舍去最高项系数,其时间复杂度为O(n²)
选择排序无论什么数据进去都是 O(n²)
的时间复杂度,所以用到它的时候,数据规模越小越好
和冒泡排序一致,相比其它排序算法,这也是一个相对较高的时间复杂度,一般情况不推荐使用
快速排序
在冒泡基础上的改进,特点是快,效率高,是处理大数据最快的排序算法之一
思路:
以从小到大排序为例,选择一个基准值(关键字/分割点/枢轴/支点)为中心,将大于该值的放在该值右边,小于该值的放在该值左边(紧挨着中心值放)