JavaScript常用排序算法总结

(一)冒泡排序

原理:

比较相邻的元素,如果第一个比第二个大,就交换他们两个;
对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对;
在这一点,最后的元素应该会是最大的数;
针对所有的元素重复以上的步骤,除了最后一个;
持续每次对越来越少的元素重复上面的步骤,
直到没有任何一对数字需要比较。

function bubbleSort(arr){
	console.time('time:')
	var len = arr.length;
	for(var j = 0 ; j < len ; j++){//n个元素需要循环n次
		for(var k = 0 ; k < len - j - 1 ; k++ ){//每次找到的元素都会排到末尾,所以k每次都从0开始,外层循环每次可以找到一个正确的元素,所以内循环只需要 len-j 次,为了防止数组越界,所以还要减一
			if(arr[k] > arr[k+1]){//顺序不对,两个元素交换
				var t = arr[k];
				arr[k] = arr[k+1];
				arr[k+1] = t;
			}
		}
	}
	console.timeEnd('time:');
	return arr;
}

时间复杂度最好为o(n)  最坏为(n^2)  平均为o(n^2)   空间复杂度为o(1)  稳定

(二)简单选择排序

原理:

简单选择排序的基本思想:给定数组:int[] arr={里面n个数据};
第1趟排序,在待排序数据arr[1]~arr[n]中选出最小的数据,
将它与arrr[1]交换;第2趟,
在待排序数据arr[2]~arr[n]中选出最小的数据,将它与r[2]交换;
以此类推,第i趟在待排序数据arr[i]~arr[n]中选出最小的数据,
将它与r[i]交换,直到全部排序完成。

function selectionSort(arr){
	console.time('time:')
	var len = arr.length;
	for(var i = 0 ; i < len ; i++){//n个元素,就有n个位置,需要循环n次
		for(var j = i+1 ; j < len ; j++){//选择排序每次都会找到一个正确的元素放到前面,所以第二层索引从i开始,需要和剩下的所有的元素比较,所以 j < len 
			if(arr[i] > arr[j]){//i是待比较的位置,分别和未排序的所有元素比较,顺序不对的就交换
				var t = arr[i];
				arr[i] = arr[j];
				arr[j] = t;
			}
		}
	}
	console.timeEnd('time:');
	return arr;
}

时间复杂度最好为o(n^2) 最坏为(n^2) 平均为o(n^2)   空间复杂度为o(1)  不稳定

(三)直接插入排序

原理:

从第一个元素开始,该元素可以被认为已经被排序,
取出下一个元素,在已经排好序的序列中从后往前扫描,
直到找到小于或者等于该元素的位置,
将该位置后面的所有已排序的元素从后往前依次移一位,
将该元素插入到该位置。

扫描二维码关注公众号,回复: 3574696 查看本文章
function insertionSort(arr){
	var len = arr.length;
	for(var i = 1 ; i < len ; i++){//把第一个元素当作已排序序列,所以i从1开始
		var t = arr[i];//先保存第i个位置的元素,以免被覆盖
		var j = i - 1;//第i个元素的前面的元素是已经排好序的,从后往前比较,所以是i-1
		while(t < arr[j] && j >= 0){//带插入元素需要插入到第一个比自己小的元素的前面,所以比待比较元素大的都往后挪一个位置
			arr[j+1] = arr[j];
			j--;
		}
		arr[j+1] = t;
	}
	return arr;
}

时间复杂度最好为o(n) 最坏为(n^2) 平均为o(n^2)   空间复杂度为o(1) 稳定

(四)希尔排序

原理:

选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
按增量序列个数k,对序列进行k 趟排序;
每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

function shellSort(arr){
	var len = arr.length,
		t,
		gap = 1;
	console.time('time:');
	while(gap < len / 5){//动态计算间隔序列
		gap = gap * 5 + 1;
	}
	for(gap; gap > 0 ; gap = Math.floor(gap/5)){//计算下一个间隔,循环内的算法和直接选择排序一样,只是间隔改为gap,可以理解为把1替换为gap
		for(var i = gap ; i < len ; i += gap){
			t = arr[i];
			for(var j = i - gap; t < arr[j] && j >= 0 ; j -= gap){
				arr[j+gap] = arr[j]
			}
			arr[j+gap] = t;
		}
	}
	console.timeEnd('time:');
	return arr;
}

时间复杂度最好为o(nlog2 n) 最坏为(nlog2 n) 平均为o(nlog n)   空间复杂度为o(1) 不稳定

(五)归并排序

原理:

把长度为n的输入序列分成两个长度为n/2的子序列;
对这两个子序列分别采用归并排序;
将两个排序好的子序列合并成一个最终的排序序列。

function divide(arr){
	var len = arr.length;
	if(len < 2 )//数组长度分割到最小了,不用再分了,这里只能是2,和merge的写法有关,同时也是递归的停止条件
		return arr;
	var middle = Math.floor(len / 2);//求数组的分割点,即数组的中点
	var left = arr.slice(0, middle);//分割数组
	var right = arr.slice(middle);

	return merge(divide(left), divide(right));//数组分割到最小的单位后开始排序和合并
}
function merge(arrL, arrR){
	var res = [];
	while(arrL.length && arrR.length){
		if(arrL[0] > arrR[0]){//传进来的数组的最小长度是1,可以当作有序的,所以只需要分别比较第一个元素
			res.push(arrR.shift());
		}else{
			res.push(arrL.shift());
		}
	}

	if(arrL.length){
		res = res.concat(arrL);//把剩下的元素拼接的结果数组的后面
	}

	if(arrR.length){
		res = res.concat(arrR);
	}
	return res;
}
function mergeSort(arr){
	console.time('time:');
	var res = divide(arr);//divide()递归地把数组分割
	console.timeEnd('time:');
	return res;
}

时间复杂度最好为o(n) 最坏为(nlogn) 平均为o(nlogn)   空间复杂度为o(n) 稳定

猜你喜欢

转载自blog.csdn.net/let4897/article/details/83036319