常见十大算法

优劣术语
- 稳定性 原本ab前,a=b,排序之后位置任然不变。不稳定性则相反
- 内排序 所有排序都在内存中完成。外排序数据放磁盘,排序通过磁盘内存的数据传输
- 事件复杂度 算法执行耗费的时间
- 空间复杂度 算法执行耗费的内存
算法
In/out-place: 不占/占额外内存

  1. 冒泡排序:

- 比较相邻的元素。如果第一个比第二个大,就交换它们两个
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数
- 针对所有的元素重复以上的步骤,除了最后一个
- 重复步骤1~3,直到排序完成
- console.time()/timeEnd(),相同参数即可显示之间的时间
function sortArray(arr) {
	let tmp;
	for (let i = 0; i < arr.length-1;i++) {
		for(let j = 0 ; j < arr.length-1;j++){
			if(arr[j] > arr[j+1]){
				tmp = arr[j];
				arr[j] = arr[j+1];
				arr[j+1] = tmp;
			}
		}
	}
}

改进1:设置标志位pos,每一层排完序之后,就记录排到最大的哪一位在什么位置,因为每一层最大的数就是它所在数组的倒数的位数,下一次就没必要再循环一遍

function sortArray(arr) {
	let i = arr.length-1;
	while(i > 0) {
		var pos = 0;
		for(let j = 0 ; j < i;j++){
			if(arr[j] > arr[j+1]){
				pos = j;
				var tmp = arr[j];
				arr[j] = arr[j+1];
				arr[j+1] = tmp;
			}
		}
		i = pos;
	}
}

改进2:每趟排序从正反向冒泡一次得到两个最终值(最大和最小值),排序次数几乎减少一半

function sortArray(arr) {
	let low = 0;
	let high = arr.length-1;
	while(low < high) {
		for (var i = low; i < high; i++) {
			if (arr[i] > arr[i+1]) {
				var tmp = arr[i];
				arr[i] = arr[i+1];
				arr[i+1] = tmp;
			}
		}
		--high;
		for(let j = high ; j > low ;j--){
			if(arr[j] < arr[j-1]){
				var tmp = arr[j];
				arr[j] = arr[j-1];
				arr[j-1] = tmp;
			}
		}
		++low;
	}
}

冒泡

  1. 选择排序:

首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。

function sortArray(arr) {
	for (let i = 0; i < arr.length-1;i++) {
		let pos = i;
		for(let j = i +1; j < arr.length;j++){
			if(arr[pos] > arr[j]){
				pos = j;
			}
		}
		let tmp = arr[i];
			arr[i] = arr[pos];
			arr[pos] = tmp;
	}
}

选择

  1. 插入排序:

从第一个元素开始,该元素可以认为已经排好序,取下一个,在已经排好序的序列中向前扫描,有元素大于这个新元素,将已经在排好序中的元素移到下一个位置,依次执行

function sortArray(arr){
	for (var i = 1; i < arr.length; i++) {
		var tmp = arr[i];
		for(var j = i -1; j>=0 && arr[j] > tmp; j--){
			arr[j+1] = arr[j];
		}
		arr[j+1] = tmp;
	}
}

改进:插入时使用二分查找

function sortArray(arr){
	for (var i = 1; i < arr.length; i++) {
		var tmp = arr[i],left=0,right=i-1;
		while (left <= right) {
			var mid = parseInt((left+right)/2);
			if (tmp < arr[mid] ) {
				right = mid -1;
			}else {
				left = mid +1;
			}
		}
		for(var j = i -1; j>=left; j--){
			arr[j+1] = arr[j];
		}
		arr[left] = tmp;
	}
}

插入

  1. 希尔排序:

先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序

function sortArray(arr){
	var len = arr.length,tmp,gap =1;
	while(gap < len/4){ //定义间隔序列
		gap = gap*4 +1;
	}
	for (gap; gap > 0; gap = Math.floor(gap / 4 )) {
		for(var i = gap; i< len;i++){
			tmp = arr[i];
			for (var j = i - gap; j >= 0 && arr[j] > tmp; j -= gap) {
				arr[j + gap] = arr[j];
			}
			arr[j + gap] = tmp;
		}	
	}
}

希尔

  1. 归并排序:

将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序

function mergeSort(arr) {
	var len = arr.length;
	if(len < 2){
		return arr;
	}
	var middle = Math.floor(len/2),
	left = arr.slice(0, middle),
	right = arr.slice(middle);
	return merge(mergeSort(left),mergeSort(right));
}
function merge(left,right){
	var result =[];
	while(left.length && right.length){
		if (left[0] <= right[0]) {
			result.push(left.shift());
		}else {
			result.push(right.shift());
		}
	}
	while (left.length) {
		result.push(left.shift());
	}while (right.length) {
		result.push(right.shift());
	}
	return result;
}

归并

  1. 快速排序:

function sortArray(a){
	if (a.length <=1) {
		return a;
	}
	var num = Math.floor(a.length/2);
	var centerVal = a.splice(num,1); //获取中间值
	var left =[];
	var right =[];
	for (var i = 0; i < a.length; i++) {
		if (a[i] < centerVal) {
			left.push(a[i]);
		}else {
			right.push(a[i]);
		}
	}
	return sortArray(left).concat(centerVal,sortArray(right));
}

快排

  1. 堆排序:

近似完全二叉树个数为:2n-1,同时满足子节点的键值或索引总是小于或大于它的父节点

function heapSort(array) {
    if (Object.prototype.toString.call(array).slice(8, -1) === 'Array') {
        //建堆
        var heapSize = array.length, temp;
        for (var i = Math.floor(heapSize / 2) - 1; i >= 0; i--) {
            heapify(array, i, heapSize);
        }
 
        //堆排序
        for (var j = heapSize - 1; j >= 1; j--) {
            temp = array[0];
            array[0] = array[j];
            array[j] = temp;
            heapify(array, 0, --heapSize);
        }
        return array;
    } else {
        return 'array is not an Array!';
    }
}
/*方法说明:维护堆的性质
@param  arr 数组
@param  x   数组下标
@param  len 堆大小*/
function heapify(arr, x, len) {
    if (Object.prototype.toString.call(arr).slice(8, -1) === 'Array' && typeof x === 'number') {
        var l = 2 * x + 1, r = 2 * x + 2, largest = x, temp;
        if (l < len && arr[l] > arr[largest]) {
            largest = l;
        }
        if (r < len && arr[r] > arr[largest]) {
            largest = r;
        }
        if (largest != x) {
            temp = arr[x];
            arr[x] = arr[largest];
            arr[largest] = temp;
            heapify(arr, largest, len);
        }
    } else {
        return 'arr is not an Array or x is not a number!';
    }
}

堆排序

  1. 计数排序:

使用一个额外的数组C,其中第i个元素是待排序数组A中值等于i的元素的个数,然后根据数组C来将A中的元素排到正确的位置,它只能对整数进行排序

function countingSort(array) {
    var len = array.length,
        B = [],
        C = [],
        min = max = array[0];
    for (var i = 0; i < len; i++) {
        min = min <= array[i] ? min : array[i];
        max = max >= array[i] ? max : array[i];
        C[array[i]] = C[array[i]] ? C[array[i]] + 1 : 1;
    }
    for (var j = min; j < max; j++) {
        C[j + 1] = (C[j + 1] || 0) + (C[j] || 0);
    }
    for (var k = len - 1; k >= 0; k--) {
        B[C[array[k]] - 1] = array[k];
        C[array[k]]--;
    }
    return B;
}

计数

  1. 桶排序:

\- 设置一个定量的数组当作空桶
\- 遍历输入数据,并且把数据一个一个放到对应的桶里去
\- 对每个不是空的桶进行排序
\- 从不是空的桶里把排好序的数据拼接起来
/*方法说明:桶排序
@param  array 数组
@param  num   桶的数量*/
function bucketSort(array, num) {
    if (array.length <= 1) {
        return array;
    }
    var len = array.length, buckets = [], result = [], min = max = array[0], regex = '/^[1-9]+[0-9]*$/', space, n = 0;
    num = num || ((num > 1 && regex.test(num)) ? num : 10);
    for (var i = 1; i < len; i++) {
        min = min <= array[i] ? min : array[i];
        max = max >= array[i] ? max : array[i];
    }
    space = (max - min + 1) / num;
    for (var j = 0; j < len; j++) {
        var index = Math.floor((array[j] - min) / space);
        if (buckets[index]) {   //  非空桶,插入排序
            var k = buckets[index].length - 1;
            while (k >= 0 && buckets[index][k] > array[j]) {
                buckets[index][k + 1] = buckets[index][k];
                k--;
            }
            buckets[index][k + 1] = array[j];
        } else {    //空桶,初始化
            buckets[index] = [];
            buckets[index].push(array[j]);
        }
    }
    while (n < num) {
        result = result.concat(buckets[n]);
        n++;
    }
    return result;
}

桶

  1. 基数排序:

\- 取得数组中的最大数,并取得位数
\- arr为原始数组,从最低位开始取每个位组成radix数组
\- 对radix进行计数排序 \(利用计数排序适用于小范围数的特点\)
/**
 * 基数排序适用于:
 *  (1)数据范围较小,建议在小于1000
 *  (2)每个数值都要大于等于0
 * @param  arr 待排序数组
 * @param  maxDigit 最大位数
 */
//LSD Radix Sort
 
function radixSort(arr, maxDigit) {
    var mod = 10;
    var dev = 1;
    var counter = [];
    for (var i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
        for(var j = 0; j < arr.length; j++) {
            var bucket = parseInt((arr[j] % mod) / dev);
            if(counter[bucket]== null) {
                counter[bucket] = [];
            }
            counter[bucket].push(arr[j]);
        }
        var pos = 0;
        for(var j = 0; j < counter.length; j++) {
            var value = null;
            if(counter[j]!=null) {
                while ((value = counter[j].shift()) != null) {
                      arr[pos++] = value;
                }
          }
        }
    }
    return arr;
}

基数
11.sort()
function compare(a,b){return a - b ;}//b-a 从大到下,对于数值类型或者valueOf()返回数值类型的得对象类型 function compare(a,b){ if( a > b){ return 1; }else if (a < b) { return -1; }else { return 0; } } var B =['a','b','c','ac','abc','ca','ba'];*/ B.sort(); console.log(B); //[ 'aa', 'abc', 'ac', 'b', 'ba', 'c', 'ca' ] var C = ['1','10','2','3','13','31','21']; C.sort(function(a,b){return a-b;}); console.log(C);
参考

猜你喜欢

转载自blog.csdn.net/u013270347/article/details/80604690