冒泡排序、插入排序、选择排序、快速排序、希尔排序和归并排序的算法实现

1.冒泡排序

冒泡排序基本思想:两两比较相邻记录的关键字,如果反序则交换位置,直到没有反序记录为止。

过程:遍历每个元素,每次与其后的元素比较,顺序错误就交换位置,重复进行直到不需要交换。这个算法名字的由来是因为越小的元素经由交换慢慢“浮”到数列的顶端。

代码实现如下:

function bubbleSort(arr){
	var len = arr.length;
	var temp = [];//创建一个临时数组
	for(var i=0;i<len;i++){
		for(var j=0;j<len-i-1;j++){
			if (arr[j] > arr[j+1]) {//遍历的元素与相邻的后一个元素进行比较
				//注意:这里赋值运算符的右边是值,左边是数组索引号
				temp = arr[j+1];//把小的元素值存进临时数组里
				arr[j+1] = arr[j];//把大的元素值赋值给索引值大的
				arr[j] = temp;//把临时数组里的元素值赋值给索引值小的
			}
		}
	}
	return arr;
}

console.log(bubbleSort([1,4,9,4,7,2,4,7,6]))//[ 1, 2, 4, 4, 4, 6, 7, 7, 9 ]

2.插入排序

插入排序基本思想:将一个记录插入到已排好序的有序表中,从而得到一个新的、记录数增1的有序表。

过程:第一个元素默认已排序,每次遍历下一元素,在已排序的元素序列中从后向前扫描每个元素并与之一一比较,如果遍历元素小于已排序元素,则将遍历元素插入到已排序元素的位置。

代码实现如下:

function insertionSort(arr){
	var len = arr.length;
	var preIndex,current;
	for(var i=1;i<len;i++){
		preIndex = i - 1;//已排序的最后一个元素的索引值
		current = arr[i];//将取到的当前元素值赋给current,而不是赋上索引值!
		//先将已排序的最后一个元素值与取到的当前元素值进行比较(第一次比较)
		while(preIndex >= 0 && arr[preIndex] > current){
			//如果大于,则将已排序的最后一个元素值赋给在其后面的一个元素(把值互换位置,索引不变)
			arr[preIndex + 1] = arr[preIndex];
			//因为是将取出的当前元素通过在已排序的元素序列中从后向前扫描(所以要递减)的元素进行比较,如果前一个
			preIndex--;
			//如果一直大于,那么就比较值互换之后的元素与其前一个元素进行比较(第二次比较),值再次互换,直到不大于
		}
		arr[preIndex + 1] = current;//如果不是前一个元素大于其后一个元素,那么前一个元素值与其后一个元素值不互换
	}
	return arr;
}

console.log(insertionSort([1,4,9,4,7,2,4,7,6]))//[ 1, 2, 4, 4, 4, 6, 7, 7, 9 ]

3.选择排序

选择排序基本思想:是通过n-i次关键字间的比较,从n-i个记录中选出关键字最小的额记录,并和第i个记录交换位置。

过程:先在未排序序列中找到最小(大)元素,存放在已排序序列的起始位置;然后从剩余未排序元素中继续寻找最小(大)元素,然后放在已排序的末尾,直到所有元素排序完毕。

代码实现如下:

function selectionSort(arr){
	var len = arr.length;
	var minIndex,temp;
	for(var i=0;i<len;i++){
		minIndex = i;//将i的值赋给最小索引变量
		for(var j=i+1;j<len;j++){
			if(arr[minIndex] > arr[j]){//当前元素与其后所有元素逐一比较
				//当前元素值一旦大于其后某一元素的值,那么便把小元素所在的索引值赋给minIndex
				//接下来进行比较的时候,就是将上一次比较得到的小元素再与在其之后的元素逐一比较,再次寻找较小元素
				//直到找到最小的元素,并把最小元素的索引赋值给minIndex
				minIndex = j;
			}
		}
		//每次找到最小元素后便把这个小元素放在每次循环的第一个位置
		temp = arr[i];//将当前元素对应的值存进temp
		arr[i] = arr[minIndex];//把最小元素的值赋给当前元素索引对应的值
		arr[minIndex] = temp;//把当前元素的值赋给最小元素所在的位置(索引)
		//也就是说上述三行代码的意思是将两个比较的元素的值互换
	}
	return arr;
}

console.log(selectionSort([1,4,9,4,7,2,4,7,6]))//[ 1, 2, 4, 4, 4, 6, 7, 7, 9 ]

4.快速排序

快速排序基本思想(过程):

第一,在数据集之中选择一个元素作为基准;

第二,数组(除开基准值)里的每个元素与基准进行比较,所有小于基准的元素都放在左边的数组里;所有大于基准的元素都放在右边的数组里;

第三,对左边和右边的两个子集不断的重复第一步和第二步,直到所有子集只剩下一个元素为止;

第四,将所有子集拼接形成一个已排序的数组。

代码实现如下:

function quickSort(arr){
	if (arr.length <= 1) {
		return arr;
	}
	var pivotIndex = Math.floor(len/2);//为了取数组基准(中间值)而准备的索引
	var pivot = arr.splice(pivotIndex,1)[0];//选出基准值(中间元素)
	var left = [],right = [],len = arr.length;
	for(var i=0;i<len;i++){
		if(arr[i] < pivot){//数组的各个元素(除了基准元素,这个时候的arr是删除了基准的数组)与基准元素比较,小的元素放在左边数组
			left.push(arr[i]);
		}else{
			right.push(arr[i]);//大的元素放在右边数组里
		}
	}
	return quickSort(left).concat([pivot],quickSort(right));//重复上述操作,直至排序完成,最后拼接左边数组+基准值+右边数组
}

console.log(quickSort([1,4,9,4,7,2,4,7,6]))//[ 1, 2, 4, 4, 4, 6, 7, 7, 9 ]

5.希尔排序

希尔排序基本思想:它是第一个突破O()的排序算法,是简单插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。实质是分组插入排序,希尔排序又称缩小增量排序。

过程:把记录按步长(两元素间隔)gap分组,对每组记录采用直接插入排序方法进行排序;随着步长逐渐减小,每个分组包含的记录越来越多;当步长的值减小到1时,整个数据合成一组,构成一组有序记录,则完成排序。

代码实现如下:

function shellSort(arr) {
    var len = arr.length,
    	gap = Math.floor(len/2);//两个数的间隔向下取整
    while(gap >= 1){//两个数的间隔必须不小于1
    	for(var i=gap;i<len;i++){
    		var j,temp=arr[i];//把遍历的值(靠后)暂时存进temp
    		for(j=i-gap;j>=0&&temp<arr[j];j=j-gap){//前面的元素与间隔后的数做比较
    			arr[j+gap]=arr[j];//如果后面的数比前面的数小,那么两个数互换位置
    		}
    		arr[j+gap]=temp;//否则位置不变
    	}
    	gap = Math.floor(gap/2);//继续重复操作,知道gap<1跳出循环
    }
    return arr;
}

console.log(shellSort([1,4,9,4,7,2,4,7,6]))//[ 1, 2, 4, 4, 4, 6, 7, 7, 9 ]

6.归并排序

归并排序的基本思想:该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若有两个有序表合并成一个有序表,称为2-路归并。

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

代码实现如下:

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){//将左右两个子序列作为merge函数(辅助函数)的两个参数
	var result = [];
	while(left.length > 0 && right.length > 0){
		if(left[0] <= right[0]){//左边序列的第一个元素和右边序列的第一个元素比较,小的元素则被放入到result中
			//这里要着重理解为什么要用shift,shift是删除数组第一个元素并返回
			//如果数组中有多个元素,删除第一个,那么接下来第二个就变成第一个,然后继续选出来被比较,直到数组的长度为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;
}

console.log(mergeSort([1,4,9,4,7,2,4,7,6]))//[ 1, 2, 4, 4, 4, 6, 7, 7, 9 ]



猜你喜欢

转载自blog.csdn.net/charles_tian/article/details/80967523