选择排序-简单选择排序、堆排序算法

选择排序是一类借助选择进行排序的方法,主要思想:每趟排序在当前待排序序列中选出关键码最小的记录,添加到有序序列中。特点是记录移动的次数较少。

一、简单选择排序

选择排序是一种简单直观的排序算法,无论什么数据进去都是O(n2) 的时间复杂度。所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。通俗来说就是你们中间谁最小谁就出列,站到队列的最后边,然后继续对着剩余的无序数组说你们中间谁最小谁就出列,站到队列的最后边,一直到最后一个,继续站到最后边,这样数组就有了顺序,从小到大。

基本思想:

  第i趟排序在待排序序列arr[i]-arr[n](1<=i<=n-1)中选取关键码最小的记录并和第i个记录交换作为有序序列的第i个记录。

function selectSort(arr){
    var len=arr.length;
    var temp;
    for(var i=0;i<len-1;i++){
        index=i;
        for(var j=i+1;j<len;j++){
            if(arr[j]<arr[index]){ // 寻找最小的数 保存索引
                index=j;                   
            }
        }
        if(index!=i){
            temp=arr[index];
            arr[index]=arr[i];
            arr[i]=temp;
        }
    }
    return arr;
}
console.log(selectSort([4,3,2,1,5,6,7]));

 效率:

时间复杂度:最好:O(N2),最坏:O(N2),平均:O(N2)。

空间复杂度:O(1)。

稳定性:不稳定

二、堆排序

首先明确完全二叉树概念:

  深度为k,有n个结点的二叉树当且仅当其每一个结点都与深度为k的满二叉树中编号从1至n的结点一一对应时,称为完全二叉树。

其次明确堆的概念:

  堆是具有以下性质的完全二叉树,每个结点的值小于或等于其孩子结点的值(小根堆),每个结点的值大于或等于其孩子结点的值(大根堆)

堆排序分为两个过程:

1.建堆。

  堆实质上是完全二叉树,必须满足:树中任一非叶子结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字。堆分为:大根堆和小根堆,升序排序采用大根堆,降序排序采用小根堆。如果是大根堆,则通过调整函数将值最大的节点调整至堆的根结点。

  伪代码:

  1.设置i和j,分别指向当前要筛选的结点和要筛选结点的左孩子;

  2.若结点i已是叶子,则筛选完毕,算法结束;否则执行下述操作;

    2.1 将j指向结点i 的左右孩子的较大者;

    2.2 如果arrr[i]>arr[j],则筛选完毕,算法结束;

           2.3 如果arr[i]<arr[j],则将arr[i]与arr[j]交换;另i=j,转步骤2继续筛选;

筛选法调整堆的算法:

//筛选法调整堆函数
function headAdjust(arr, k, m) {
    //将当前节点值(即将被筛选的节点)进行保存
    var i = k;
    var filter = arr[k];
    var temp;
    //定位到当前节点的左孩子节点
    var j = i * 2 + 1;
    //递归,直至没有子节点为止(筛选还没有进行到叶子)
    while (j < m) {
        //比较i的左右孩子,j指向较大者,如果当前节点有右边的子节点,并且右子节点较大,采用右子节点
        if (j + 1 < m && arr[j] < arr[j + 1]) {
            j++;
        }

        if (arr[i] > arr[j]) { //根节点已经大于孩子节点中的较大者
            break;
        } else {
            temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
            i = j;
            j = i * 2 + 1;
        }
    }
}

初始建堆:

//初始建堆
function buildHeap(arr) {
    //从最后一个分支节点到根节点
    for (var i = arr.length / 2; i >= 0; i--) {
        headAdjust(arr, i, arr.length);
    }
}

2.将堆的根结点保存于尾部,并对剩余序列调用调整函数,调整完成后,再将最大跟保存于尾部,再对剩余序列进行调整,反复进行该过程,直至排序完成。

//堆排序函数
function sort(arr) {
    //初始建堆
    buildHeap(arr);
    var len = arr.length;
    var temp;
    //从堆尾部开始调整
    /*for(var i=arr.length-1; i>0; i--){
      temp = arr[i];
      arr[i] = arr[0];
      arr[0] = temp;
      //进行调整,将最大元素调整至堆顶
      headAdjust(arr, 0, i);
    }*/
    //从堆首开始调整
    for (var i = 0; i < len; i++) {
        //堆顶永远是最大元素,故将堆顶和尾部元素交换,将最大元素保存于尾部,并且不参与后面的调整
        temp = arr[0];
        arr[0] = arr[len - (i + 1)];
        arr[len - (i + 1)] = temp;

        //进行调整,将最大元素调整至堆顶
        headAdjust(arr, 0, len - (i + 1));
    }
}

调用:

var arr = [36, 30, 18, 40, 32, 45, 22, 50];
console.log('before: ' + arr);
sort(arr);
console.log(' after: ' + arr);

 效率:

时间复杂度:最好:O(nlog2n),最坏:O(nlog2n),平均:O(nlog2n)。

空间复杂度:O(1)。

稳定性:不稳定

原文地址:https://www.cnblogs.com/Iona/p/4724878.html