常见排序算法

不写下来,每次查资料感觉都没什么耐心看啊,真是令人惆怅,所以还是要自己捋一遍的。盗张图:


直接插入排序:

从第一个数开始,每次将一个待排序的数,插入到已经排列好的数列中的适当位置,使数列有序,直到所有元素都在新数列为止。

举例:
数组:【】89 46 36 09 52 91

第一次:【89】46 36 09 52 91

第二次:【46 89】36 09 52 91

第三次:【36 46 89】09 52 91

第四次:【09 36 46 89】52 91

第五次:【09 36 46 52 89】91

第六次:【09 36 46 52 89 91】

function insertionSort(arr) {
    var len = arr.length;
    var preIndex, current;
    for (var i = 1; i < len; 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;
}
复制代码

希尔排序:

相当于一种分组直接插入排序,原理即每次设置一个间隔,对有同样间隔的两个数作为一组进行插入排序即比大小,按照比大小的结果决定是否互换位置,然后继续下一组排序,知道全部数据都排一遍。继续设置更小的间隔按照上面的步骤排,直到最后一轮间隔为1时得出的新数列即为最后排序结果。

举例:


依次类推,第二次间隔为2,排序结果为:2  1  0  4  3  8  6  5  9  7

第三次间隔为1,排序结果为:0  1  2  3  4  5  6  7  8  9

function shellSort(arr) {
    var len = arr.length,
        temp,
        gap = 1;
    while(gap < len/3) {          //动态定义间隔序列
        gap =gap*3+1;
    }
    for (gap; gap> 0; gap = Math.floor(gap/3)) {
        for (var i = gap; i < len; i++) {
            temp = arr[i];
            for (var j = i-gap; j > 0 && arr[j]> temp; j-=gap) {
                arr[j+gap] = arr[j];
            }
            arr[j+gap] = temp;
        }
    }
    return arr;
}
复制代码

直接选择排序:
第一次从第1到n个数中选出最小值,放在第一位,

第二次从第2个到第n个中选出最小值,放在第二位,

。。。

第n-1次从第n-1个到n个中选出最小值,放在第n-1位。

举例:

数组:【】89 46 36 09 52 91

第一次:【09】89 46 36 52 91

第二次:【09 36】89 46  52 91

第三次:【09 36 46】89 52 91

第四次:【09 36 46 52】89 91

第五次:【09 36 46 52 89】91

代码实现:

function selectSort(arr){
    let len=arr.length,minIndex;//minIndex记录最小的索引
    for(var i=0;i<len-1;i++){
        minIndex=i;  //记录最小的索引
        for(var j=i+1;j<len;j++){
            if(arr[j]<arr[minIndex]){
                minIndex=j;
            }
        }
        if(i!=minIndex){
            var temp =arr[i];
            arr[i]=arr[minIndex];
            arr[minIndex]=temp;
        }
    }
    return arr;
}
selectSort(arr);
复制代码

堆排序:

堆排序是一种树形选择排序,将数组看成是一棵二叉树的顺序结构存储,然后利用完全二叉树中双亲结点和孩子结点之间的的关系来调整每一层关系。

画图好费劲,不想画图了,举个例子:
数组:20 70 30 80 90 60 10 50 40 

从左到右排成二叉树的形状就是:
                               20                                                                   结点1

               70                               30                                                结点2、3

        80               90          60                 10                                    结点4、5、6、7

50              40                                                                                结点8、9

按照二叉树中子结点的数值要小于等于父结点,所以从最下面一层起,分别把左右孩子结点和对应的父结点做比较,如果小于等于父结点则不做变动,如果大于父结点就跟父结点交换数据。所以第一轮交换后,再检查二叉树,把不符合规则的重新排序,得到的结果就是:

                                 90

                  80                            60

        50                  70        30               10

20             40

此时得到数组中最大值90,在二叉树最顶端的父节点,此时的数组为:90 80 60 50 70 30 10 20 40 ,将第一位与最后一位交换位置,即:40 80 60 50 70 30 10 20 【90】作为新数组重新开始进行排序,其中90不再参与排序,以此类推,完成排序。

var len;    //因为声明的多个函数都需要数据长度,所以把len设置成为全局变量

function buildMaxHeap(arr) {   //建立大顶堆
    len = arr.length;
    for (var i = Math.floor(len/2); i &gt;= 0; i--) {
        heapify(arr, i);
    }
}

function heapify(arr, i) {     //堆调整
    var left = 2 * i + 1,
        right = 2 * i + 2,
        largest = i;

    if (left < len && arr[left] > arr[largest]) {
        largest = left;
    }

    if (right < len && arr[right] > arr[largest]) {
        largest = right;
    }

    if (largest != i) {
        swap(arr, i, largest);
        heapify(arr, largest);
    }
}

function swap(arr, i, j) {
    var temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

function heapSort(arr) {
    buildMaxHeap(arr);

    for (var i = arr.length-1; i > 0; i--) {
        swap(arr, 0, i);
        len--;
        heapify(arr, 0);
    }
    return arr;
}
复制代码

冒泡排序:

以第一个数为基准,跟剩下的数字一一对比,如果比基准数大就互换位置,设置新的基准数,如果比基准数小就继续往下比较下一个数,效果是每执行一轮能够选出一个最大的数放在最右边,接着开始第二轮,选出第二大的数字放在倒数第二位,以此类推。

数组:89 46 36 09 52 91

第一轮以89为基准:46 36 09 52 89 【91】

第二轮以46为基准:36 09  46(此时跟52比较时,基准数字换为52)52(此时跟89比较时,基准数字换为89)【89 91】

第三轮以36为基准: 09 36 46 【52 89 91】

第四轮以09为基准:09 36 【46 52 89 91】

代码实现:

function bubbleSort(arr){
    for(let i=0,l=arr.length;i<l;i++){
        for(let j=i+1;j<l;j++){
            if(arr[i]>arr[j]){
                let temp=arr[i];
                arr[i]=arr[j];
                arr[j]=temp;
            }
        }
    }
    return arr;
}
bubbleSort(arr);
复制代码

快速排序:

总结出来就是选择一个数为基准,比它大的往后放,比它小的往前放。一轮完毕再重新选择基准,以此类推。

具体过程:一般选择第一个数作为第一轮基准数,倒序从最后一个开始,跟基准数做对比,找到一个比基准数小的就把这个数放在原来基准数的位置,接着从正序第二个开始找到比基准数大的数字就把这个数字填在刚刚比基准数小的数空出来的位置。接着继续倒序从被替换位置开始找比基准数小的数字,找到就把这个数填在正序时大于基准数的数字空出来的位置,直到,所有的数都被找一遍会空出来一个位置,就把基准数放在这个位置,此时基准数左边的数都小于它,基准数右边的数都大于它。从第二轮开始将分区作比较,即第一轮基准数的左右两边将分别作为两个不同的区,找不同的基准数开始重复上一轮动作排序,直到所有的数都排好序。

数组:

20 70 30 80 90 60 10 50 40  

第一轮以20为基准,未填值位用括号代替占位:
从右往左找比20小的数字,找到10,所以数组顺序变为:10 70 30 80 90 60 ()50 40

从左往右找比20大的数字,找到70,所以数组顺序变为:10 () 30 80 90 60 70 50 40

从右往左找比20小的数字,没找到,所以数组顺序变为:10 20 30 80 90 60 70 50 40

第二轮以80为基准,因为30明显就不用再排,此处省略这一步,直接从80找:

按照上述步骤以80位基准后排序结果为:10 20 30 40 50 60 70 80 90

function quickSort(arr, left, right) {
    var len = arr.length,
        partitionIndex,
        left = typeof left != 'number' ? 0 : left,
        right = typeof right != 'number' ? len - 1 : right;

    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) {     //分区操作
    var pivot = left,                      //设定基准值(pivot)
        index = pivot + 1;
    for (var i = index; i <= right; i++) {
        if (arr[i] < arr[pivot]) {
            swap(arr, i, index);
            index++;
        }        
    }
    swap(arr, pivot, index - 1);
    return index-1;
}

function swap(arr, i, j) {
    var temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}
复制代码

归并排序:

归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

过程:把一个数组一分为二,然后把分好之后的数组再次一分为二,直到每个数组长度为1,然后两两合并成新数组进行有序合并,直到全部归并成一个数组。

盗图:


function mergeSort(arr) {  //采用自上而下的递归方法
    var len = arr.length;
    if(len < 2) {
        return arr;
    }
    var middle = Math.floor(len / 2),
        left = arr.slice(0, middle),
        right = arr.slice(middle);
    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());
        }
    }

    while (left.length)
        result.push(left.shift());

    while (right.length)
        result.push(right.shift());

    return result;
}
复制代码

基数排序(桶排序):

把所有的数字统一位数,位数不够的用0补全,设置10个桶对应数字0-9,然后从个位数开始排,个位数是什么就放到对应数字的桶里,然后按照从第0个到第9个桶里面的数字重新排序形成新数组,开始从十位数排,按照十位数上对应的数字放置到对应的桶里,再形成新数组,接着百位,千位直到最高位。

数列:73  22  93  43  55  14  28  65  39  81

第一次,根据个位数分配:
0         1            2             3            4          5           6          7          8         9

           81         22        73 93 43   14      55  65                              28       39

第二次,对新数列根据十位数分配:
0          1            2             3            4           5           6          7         8          9

           14        22  28       39          43         55          65        73       81       93

即可得到排完序的新数组。

function bucketSort(arr, bucketSize) {
    if (arr.length === 0) {
      return arr;
    }

    var i;
    var minValue = arr[0];
    var maxValue = arr[0];
    for (i = 1; i < arr.length; i++) {
      if (arr[i] < minValue) {
          minValue = arr[i];                //输入数据的最小值
      } else if (arr[i] > maxValue) {
          maxValue = arr[i];                //输入数据的最大值
      }
    }

    //桶的初始化
    var DEFAULT_BUCKET_SIZE = 5;            //设置桶的默认数量为5
    bucketSize = bucketSize || DEFAULT_BUCKET_SIZE;
    var bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1;   
    var buckets = new Array(bucketCount);
    for (i = 0; i < buckets.length; i++) {
        buckets[i] = [];
    }

    //利用映射函数将数据分配到各个桶中
    for (i = 0; i < arr.length; i++) {
        buckets[Math.floor((arr[i] - minValue) / bucketSize)].push(arr[i]);
    }

    arr.length = 0;
    for (i = 0; i < buckets.length; i++) {
        insertionSort(buckets[i]);                      //对每个桶进行排序,这里使用了插入排序
        for (var j = 0; j < buckets[i].length; j++) {
            arr.push(buckets[i][j]);                      
        }
    }

    return arr;
}
复制代码



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值