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)  不稳定

(三)直接插入排序

原理:

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

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) 稳定

(六)快速排序

原理:

从数列中挑出一个元素,称为 "基准"(pivot);
重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
 

function quickSort(arr, l, r){
	if(l > r){ //递归结束的条件
		return;
	}
	var i = l,//递归调用的时候还需要用到l和r,所以用两个变量保存l和r
		j = r,
		m = arr[i];
	while(i !== j){ //i===j代表所有元素都遍历了一遍
		while(m <= arr[j] &&  i < j){//从右往左找一个比基准元素小的元素,没找到下标往左移动一位,找到了就会跳出循环
			j--;
		}
		while(m >= arr[i] && i < j){//从左往右找一个比基准元素大的元素,没找到下标往右移动一位,找到了就会跳出循环
			i++;
		}
		//此时i和j分别是找到的元素的下标
		if(i < j){//交换两个元素
			arr[i] = arr[i] + arr[j];
			arr[j] = arr[i] - arr[j];
			arr[i] = arr[i] - arr[j];
		}
	}
	arr[l] = arr[i];//此时i===j,且处于中间,此时arr[l]的值保存在m,相当于一个空位,且arr[i] < m,所以把arr[i]放到arr[l]的位置
	arr[i] = m;//把基准元素放回中间的位置
	quickSort(arr, l, i - 1);//对基准元素左侧的元素递归排序,
	quickSort(arr, i + 1, r);//对基准元素右侧的元素递归排序
}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值