注:本文的文字解释部分并非原创,我只是对其实现用JavaScript代码来实现,以供大家学习和参考。如有错误还请不吝指出。
算法一:快速排序算法
快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要Ο(n log n)次比较。在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。
快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。
1 从数列中挑出一个元素,称为 “基准”(pivot),
2 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
3 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会退出,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。
算法步骤:
1 从数列中挑出一个元素,称为 “基准”(pivot),
2 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
3 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会退出,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
代码实现:
function quickSort (arr) {
if(arr.length <= 1){
return arr;
}
// 选择基准,并将其与原数组分离,在定义两个空数组,用来存放一左一右两个子集
var pivotIndex = Math.floor(arr.length/2);
var pivot = arr.splice(pivotIndex,1)[0];
var left = [];
var right = [];
// 然后开始遍历数组,将小于基准的元素放入左边,大于基准的放入右边
for(var i = 0;i < arr.length; i++){
if (arr[i] < pivot) {
left.push(arr[i]);
} else{
right.push(arr[i]);
}
// console.log(arr);
}
// 最后,使用递归不断重复这个过程
return quickSort(left).concat([pivot],quickSort(right));
}
console.log(quickSort([3,3,4,15,331,348,98,12]));
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
堆排序的平均时间复杂度为Ο(nlogn) 。
算法步骤:
1.创建一个堆H[0..n-1]
2.把堆首(最大值)和堆尾互换
3. 把堆的尺寸缩小1,并调用shift_down(0),目的是把新的数组顶端数据调整到相应位置
4. 重复步骤2,直到堆的尺寸为1
代码:
// 堆排序
var h = [],// 用来存放堆的数组
n;// 用来存储堆中元素的个数,也就是堆的大小
// 交换函数,交换堆中两个元素的值
function swap(x,y){
var t;
t = h[x];
h[x] = h[y];
h[y] = t;
}
// 向下调整函数
function siftdown(i){
// 传入一个需要向下调整的节点编号i,这里传入1,即从堆的定点开始向下调整
var flag = 0,// flag用来标记是否需要继续向下调整
t;
// 当i节点有儿子(其实至少有左儿子)并且需要继续调整的时候循环就执行
while(i*2 <= n && flag === 0){
// 首先判断它和左儿子的关系,并用t记录值较小的节点编号
var leftChildIndex = i*2+1,
rightChildIndex = i*2+2;
if(h[i] > h[leftChildIndex]){
t = leftChildIndex;
}else{
t = i;
}
// 如果它有右儿子,在对右儿子进行讨论
if(rightChildIndex<=n){
// 如果右儿子的值更小,更新较小的节点编号
if(h[t] > h[rightChildIndex]){
t = rightChildIndex;