JavaScript——插入排序、堆排序

一、插入排序

插入排序是一种简单直观的排序算法,它比冒泡排序 、选择排序都更有效率。

基本思路:

        插入排序的工作原理是通过构建有序序列,对于未排序元素,在已排序序列中从后向前扫描,找到对应的位置并插入。

        插入排序将数组分成“已排序”和“未排序”两部分,开始时“已排序”部分只有一个元素,然后将它后面一个元素从“未排序”部分插入到“已排序”部分中,这样,“已排序”部分增加一个元素,“未排序”部分减少一个元素。再重复该操作,直到完成全部元素的排序。

以对数组[4,3,5,1,2]进行从小到大排序为例,步骤如下:

①假定第一个元素是已排序元素,则将数组分成[4]和[3,5,1,2]这两个部分,前者是已排序部分,后者是未排序部分;

②取出未排序部分的第一个元素“3”(即前面提到的已排序部分后面一个元素),与已排序部分最后一个元素“4”比较,3<4,所以3排在4前面,数组变成[3,4]和[5,1,2]两部分;

③重复步骤②,取出未排序部分第一个元素“5”,与已排序部分最后一个元素“4”进行比较,5>4,所以5排在4后面,数组变成[3,4,5]和[1,2]两部分。

④重复步骤②,取出未排序部分第一个元素“1”,与未排序部分最后一个元素“5”比较,1<5,所以1排在5前面,继续与未排序部分倒数第二个元素“4”比较,1<4,所以1排在4前面,继续与未排序部分倒数第三个元素“3”比较,1<3,所以1排在3前面,数组变成[1,3,4,5]和[2]两部;

⑤重复步骤②,取出未排序第一个元素“2”,与未排序部分最后一个元素“5”比较,2<5,所以2排在5前面,继续与未排序部分倒数第二个元素“4”比较,2<4,所以2排在4前面,继续与未排序部分倒数第三个元素“3”比较,2<3,所以2排在3前面,继续与未排序部分倒数第四个元素“1”比较,2>1,所以2排在1后面,数组变成[1,2,3,4,5],整个排序过程结束。

时间复杂度:O(n^{2})

例:对数组[38,26,89,56,17,44]所有元素进行从小到大排序。

代码实现:

function insertSort(arr){

    var len = arr.length;   //数组的长度

    var temp;    //当前比较的值

    var i,j;      //分别是未排序和已排序数组的当前位置

    for(i=1;i<len;i++){

        j = i-1;

        temp = arr[i];

        while(j>=0 && arr[j]>temp){

            arr[j+1] = arr[j];

            j--;

        }

        arr[j+1] = temp;

    }

    return arr;

}

var arr = [38,26,89,56,17,44];

console.log("插入排序前的数组是:",arr);

arr = insertSort(arr);

console.log("插入排序后的数组是:",arr);

实现效果如下:

二、堆排序

堆排序是指利用”堆“这种数据结构所设计的一种排序算法。堆是一个二叉树,分为最大堆和最小堆。最大堆代表除了根节点以外的所有节点,其结点的值小于等于其父节点,堆中的最大元素存放于根节点中,最小堆与之相反,例如下图。

堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子节点的键值或索引总是小于(或大于)它的父节点。

完全二叉树:从根节点到倒数第二层满足完美二叉树,最后一层可以不完全填充,其叶子结点都靠左对齐。

基本思路:

以从小到大排序规则为例,先将初始待排列序列(R1,R2,…,Rn)构建成最大堆,此堆为初始的无序区;

再将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区和新的有序区,且满足R[1,2,…,n-1]<=R[n];

由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。

时间复杂度:O(nlogn)

例:对数组[38,26,89,56,17,44]所有元素进行从小到大排序。

代码实现:

建立最大堆的函数:

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

var len;

//建立最大堆(大顶堆),其实就是对arr数组做一个结构调整,使其具有堆的特性

function buildMaxHeap(arr){

    len = arr.length;

    for(var i=Math.floor(len/2);i>=0;i--){

        heapify(arr,i);

    }

}

调整数组成为最大堆的函数: 

//堆调整函数,即调整当前arr数组为最大堆

function heapify(arr,i){

    var left = 2*i+1;

    var right = 2*i+2;

    var 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;

}

本例中的测试函数: 

//测试

var arr = [38,26,89,56,17,44];

var len = arr.length;

console.log("堆排序前的数组是:",arr);

arr = heapSort(arr);

console.log("堆排序后的数组是:",arr);

实现效果如下:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值