冒泡排序
冒泡排序比较任何两个相邻的项,如果第一个比第二个大,则交换它们。元素项向上移动至正确的顺序,就好像气泡升至表面一样,冒泡排序因此得名。不推荐此算法,复杂度很高
。
function bubbleSort(array){
var length = array.length;
for (var i=0; i<length-1; i++){
for (var j=0; j<length-1-i; j++ ){
if (array[j] > array[j+1]){
var temporary = array[j];
array[j] = array[j+1];
array[j+1] = temporary;
}
}
}
};
选择排序
选择排序大致的思路是找到数据结构中的最小值并将其放置在第一位,接着找到第二小的值并将其放在第二位,以此类推。和冒泡排序一样,它包含有嵌套的两个循环,这导致了二次方的复杂度
。
function selectionSort(array){
var length = array.length,
minIndex;
for(var i=0;i<length-1;i++){
minIndex = i;
for(var j=i+1;j<length;j++){
if(array[minIndex] > array[j]){
minIndex = j;
}
};
// 排除i值等于minIndex
if(i !== minIndex){
var temporary = array[minIndex];
array[minIndex] = array[i];
array[i] = temporary;
}
}
}
插入排序
插入排序每次排一个数组项,以此方式构建最后的排序数组。假定第一项已经排序了,接着,它和第二项进行比较,第二项是应该待在原位还是插到第一项之前呢?这样,头两项就已正确排序,接着和第三项比较(它是该插入到第一、第二还是第三的位置呢?),以此类推。排序小型数组时,此算法比选择排序和冒泡排序性能要好
。
function insertionSort(array){
var length = array.length,
temporary,
index;
for(var i=1;i<length;i++){
// 要插入的元素
temporary = array[i];
// 要插入元素的索引
index = i;
// 通过比较找要插入的位置,并在比较的过程中把大的值前移一位,最后的index就是要插入的位置
while(index > 0 && array[index - 1] > temporary){
array[index] = array[index - 1];
index --;
}
array[index] = temporary;
}
}
归并排序
归并排序是一种分治算法。其思想是将原始数组切分成较小的数组,直到每个小数组只有一个位置,接着将小数组归并成较大的数组,直到最后只有一个排序完毕的大数组。并归排序性能比前三个都有很好的提升,
Mozilla Firefox使用归并排序作为 Array.prototype.sort 的实现。
function mergeSort(array){
var length = array.length;
if(length < 2){
return array;
}
var mid = Math.floor(length/2),
left = array.slice(0,mid),
right = array.slice(mid,length);
return merge(mergeSort(left),mergeSort(right));
}
function merge(left,right){
var arr = [];
while(left.length && right.length){
if(left[0] >= right[0]){
arr.push(right.shift());
}else{
arr.push(left.shift());
}
}
while(left.length){
arr.push(left.shift());
}
while(right.length){
arr.push(right.shift());
}
return arr;
}
快速排序
快速排序比上述排序算法要复杂一些,它的复杂度为O(nlogn),且它的性能通常比其他的复杂度为O(nlogn)的排序算法要好
。Chrome使用了一个快速排序的变体。以下为快速排序的逻辑:
- 首先,从数组中选择中间一项作为主元。
- 创建两个指针,左边一个指向数组第一个项,右边一个指向数组最后一个项。移动左指针直到我们找到一个比主元大的元素,接着,移动右指针直到找到一个比主元小的元素,然后交换它们,重复这个过程,直到左指针超过了右指针。这个过程将使得比主元小的值都排在主元之前,而比主元大的值都排在主元之后。这一步叫作划分操作。
- 接着,算法对划分后的小数组(较主元小的值组成的子数组,以及较主元大的值组成的子数组)重复之前的两个步骤,直至数组已完全排序。
function quickSort(array){
sort(array,0,array.length-1);
function sort(arr,left,right){
if (array.length > 1) {
var index = partition(array,left,right);
if(left < index -1){
sort(array,left,index-1);
}
if(index < right){
sort(array,index,right)
}
}
}
// 划分过程
function partition(array,left,right){
// 找主元
var pivot = array[Math.floor((right + left) / 2)],
i = left,
j = right;
// 判断是否划分完
while (i <= j) {
// 左侧寻找比主元大的值
while (array[i] < pivot) {
i++;
}
// 右侧寻找比主元小的值
while (array[j] > pivot) {
j--;
}
// 判断此时是否划分完,最后一次会出现 i > j
if (i <= j) {
// 交换两者的值
swap(array, i, j);
// 移动指针,左侧右移一位,右侧左移一位
i++;
j--;
}
}
return i;
}
function swap(array,i,j){
var temporary = array[i];
array[i] = array[j];
array[j] = temporary;
}
}