选择排序是一类借助选择进行排序的方法,主要思想:每趟排序在当前待排序序列中选出关键码最小的记录,添加到有序序列中。特点是记录移动的次数较少。
一、简单选择排序
选择排序是一种简单直观的排序算法,无论什么数据进去都是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)。
稳定性:不稳定