常用的排序算法

514 阅读3分钟

本文参考链接:www.cnblogs.com/onepixel/p/…

前言

  平时很少系统的写过排序算法,只有在用的时候才会去写,这次准备认真的分析一下各种优秀排序算法,发现自己以前对很熟悉的冒泡的理解都存在误区,这次学习受益良多,有时间的话推荐系统的分析一下各类排序算法,要用的时候根据不同情况直接就可以使用了。

1,冒泡排序

算法描述

  • 比较两个相邻的元素,如果第一个比第二个大,则交换它们的位置;
  • 注意第二层循环的结束的位置可以-i,因为后i位都是排好序的(我以前是没有-i的,会做无用功)

代码实现

function bubbleSort(arr)
{
    for(let i = 0;i<arr.length;i++)
        for(let j = 1;j+1<arr.length-i;j++)
        {
            if(arr[j]>arr[j+1])//决定是否稳定的条件,如果>=则是不稳定的
            {
                let temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    return arr;
}

复杂度分析

  • 时间复杂度:两层循环,所以O(n^2);
  • 空间复杂度:使用常量temp所以O(1);
  • 稳定性:稳定

2,选择排序

算法描述

  • 首先在未排序序列中找到最大(小)的元素,将其存放在有序列表的首部,然后继续在未排序序列中找极值,然后存在有序列表的尾部。

代码实现

function selectSort(arr)
{
    let minindex,temp;
    for(let i = 0;i<arr.length-1;i++)
    {
        minindex = i;
        for(let j = i+1;j<arr.length;j++)
        {
            if(arr[j]<arr[minindex])//寻找最小的数
                minindex = j;//修改最小值的下标
        }
        temp = arr[i];
        arr[i] = arr[minindex];
        arr[minindex] = temp;
    }
    return arr;
}

复杂度分析

  • 时间复杂度:同样两层嵌套循环,所以O(n^2);
  • 空间复杂度:使用常量temp所以O(1);
  • 稳定性:不稳定(比如 5 2 5 1)

3,插入排序

算法描述

  • 通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入;

代码实现

function insertSort(arr)
{
    let preIndex,current;
    for(let i = 1;i<arr.length;i++)
    {
        preIndex = i-1;
        current = arr[i];
        while(preIndex>=0 && arr[preIndex]>current)//在有序序列中找比当前元素大的下标
        {
            arr[preIndex+1]  = arr[preIndex];//找到之后将此元素往后移一个单位,
            preIndex--;
        }
        arr[preIndex+1] = current;//将当前元素插入指定位置
    }
    return arr;
}

复杂度分析

  • 时间复杂度:平均O(n^2);
  • 空间复杂度:常量级O(1);
  • 稳定性:稳定

4,快速排序

算法描述

  • 从数列中挑出一个元素,称为 “基准”(flag);
  • 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面,在这个分区退出之后,该基准就处于数列的中间位置。
  • 递归地把小于基准值元素的子数列和大于基准值元素的子数列排序

代码实现

function swap(arr, i, j) {
    var temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}
function quickSort(arr,left,right)
{
    let partitionIndex;
    if(left<right)
    {
        partitionIndex = partition(arr,left,right);
        quickSort(arr,left,partitionIndex-1);
        quickSort(arr,partitionIndex+1,right);
    }
    return arr;
}
function partition(arr,left,right)//分区操作
{
    let flag = left;//基准
    let index = flag+1;
    for(let i = index;i<=right;i++)
    {
        if(arr[i]<arr[flag])
        {
            swap(arr,index,i);
            index++;
        }
    }
    swap(arr,flag,index-1);
    return index-1;
}

复杂度分析

  • 时间复杂度:由于存在二分思想,所以复杂度比较低平均O(nlgn);
  • 空间复杂度:由于有递归调用占用内存,所以O(lgn);
  • 稳定性:不稳定(5 | 3 1 2 | 9 7 8 9 | 4 6 3)4会和前面的9换位置;

旨在学习和记录,可能不太详细,详细参考最上面的链接,如有不正,请多指教。