JS实现排序算法

一、前言

这篇博客是转载的,但是为了加深理解和记忆,所以按自己的思路写了一遍代码。
附上参考博客:十大经典排序算法,里面有动图。

1.1算法归类

在这里插入图片描述

二、冒泡排序

冒泡排序

/*
1.比较相邻的两个元素,如果前一个比后一个大(或者后一个比前一个小),就交换位置
2.对每一个相邻元素做同样的工作,从开始第一对到结尾最后一对,这样在最后的元素会是最大的数
3.需要重复n-1次上面的工作
*/
function bubbleSort(arr) {
	let temp;
	for(let i=0; i<arr.length-1; i++) {
		for(let j=0; j<arr.length-1-i; j++) {
			if(arr[j] > arr[j+1]) {
				temp = arr[j];
				arr[j] = arr[j+1];
				arr[j+1] = temp;
			}
		}
	}
	return arr;
}

三、选择排序

选择排序

/*
1.选中第一个位置,然后从未排序的元素中找出最小(最大)的一个放在该位置
2.经过n-1次的选择,完成排序
*/
function selectSort(arr) {
	let minIndex;
	let temp;
	for(let i=0; i<arr.length-1; i++) {
		minIndex = i;
		for(let j=i+1; j<arr.length; j++){
			if(arr[j] < arr[minIndex]) {
				minIndex = j;
			}
		}
		temp = arr[i];
		arr[i] = arr[minIndex];
		arr[minIndex] = temp;
	}
	return arr;
}

四、插入排序

插入排序

/*
1.思想上:将数组分为两堆,一堆是排好序的,一堆是没排好序的
2.数组第一个元素可以被认为是排好序的,然后我们拿到数组第二个元素的值
3.比较第二个元素与第一个元素的大小,(假设从小到大排列),如果第二个元素小于第一个元素,则将第二个元素插入到第一个元素的前面,至此,完成一次插入。
4.此时形成了由第一个元素和第二个元素组成的有序数列,以及剩下的未排序数列
5.拿到数列第三个元素的值,用这个值从有序数列的末端开始向前逐个比较,然后插入到第三个值在有序数列中应该在的位置(与第3步同理)
6.继续拿值,重复比较与插入过程。
*/

function insertSort(arr) {
	let pre_index;
	let cur_num;
	for(let i=1; i<arr.length; i++) {
		cur_num = arr[i];			//拿到当前待比较值
		pre_index = i - 1;			//pre_index指向有序数列的末尾
		while(pre_index >= 0 && cur_num < arr[pre_index]) {
			arr[pre_index + 1] = arr[pre_index];			//pre_index指向的元素向后覆盖
			pre_index--;			//pre_index指针向前移动
		}
		arr[pre_index + 1] = cur_num	//找到了cur_num应该在的位置(preindex + 1)
	}
	return arr;
}

五、归并排序

什么是归并排序

/*
	核心思想:
	1.对数组二分,然后利用递归思想逐步由下至上合并左右序列
	2.合并数组时,先由左右有序序列合并得到另一个有序序列,然后将这个序列赋值到数组对应部分
*/
function sort(arr) {
    let temp = [];          //准备一个空数组
    mergeSort(arr, 0, arr.length - 1, temp);    //调用函数来排序
}

function mergeSort(arr, left, right, temp) {
    if(left < right) {
        let mid = Math.floor((left + right) / 2);
        mergeSort(arr, left, mid, temp);        //左序列二分
        mergeSort(arr, mid+1, right, temp);     //右序列二分
        mergeArray(arr, left, mid, right, temp);  //合并左右序列并使合并后得到的有序序列赋值到原数组对应部分
    }
}

function mergeArray(arr, left, mid, right, temp) {
    let i = left;     //left不能作为指针动,后面要用,所以用i来接收left的值
    let j = mid + 1;  //right不能作为指针动,后面要用,所以用i来接收right的值
    let t = 0;        //t是临时数组指针

    while(i <= mid && j <= right) {     
        if(arr[i] <= arr[j]) {
            temp[t++] = arr[i++];
        } else {
            temp[t++] = arr[j++];
        }
    }

    while(i <= mid) {         //将左边剩余元素依次填入temp
        temp[t++] = arr[i++];
    }

    while(j <= right) {       //将右边剩余元素依次填入temp
        temp[t++] = arr[j++];
    }
    t = 0;                    //temp的指针重置

    while(left <= right) {    //将temp数组中的元素拷贝到原数组对应的部分
        arr[left++] = temp[t++];
    }
}

六、快速排序

什么是快速排序

function quickSort(arr, startIndex, endIndex) {
	if(startIndex < endIndex) {
		let pivotIndex = getPivotIndex(arr, startIndex, endIndex);
		quickSort(arr, startIndex, pivotIndex);
		quickSort(arr, pivotIndex + 1, endIndex);
	}
}

//挖坑法
function getPivotIndex(arr, startIndex, endIndex){
	
	let pivot = arr[startIndex];//先取第一个位置的元素作为基准元素
	let left = startIndex;		//左半部分指针
	let right = endIndex;		//右半部分指针
	let index = startIndex;		//坑的位置,初始等于pivot的位置


	while(left <= right){
		//先从右指针开始判断,right指针从右向左进行比较
		while(left <= right){
			if(arr[right] < pivot){			//如果当前元素小于基准元素
				arr[index] = arr[right];	//用右边的值填补空位
				index = right;				//右边形成新的空位
				left++;				//left后移
				break;				//跳出循环,然后进入左边的判断
			}
			right--;				//如果右边当前元素大于pivot,right指针左移
		}
		//left左边判断
		while(left <= right){
			if(arr[left] > pivot){		//如果当前元素大于基准元素
				arr[index] = arr[left]; //右边填补空位
				index = left;			//左边形成新的空位
				right--;				//right前移
				break;					//跳出循环,进入右边判断
			}
			left++;						//如果左边当前元素小于pivot,left指针右移
		}
	}
	arr[index] = pivot;		//找到基准元素该在的位置后赋值
	return index;
}

//指针交换法:
function getPivotIndex(arr, startIndex, endIndex){
	let left = startIndex;		//左指针
	let right = endIndex;		//右指针
	let index = startIndex;		//基准元素位置
	let pivot = arr[startIndex];	//基准元素的大小

	//大循环
	while(left < right){
		//控制右指针左移,满足条件则进行循环,不满足则退出
		while(left < right && arr[right] >= pivot){
			right--;
		}
		//控制左指针右移,满足条件则进行循环,不满足则退出
		while(left < right && arr[left] <= pivot){
			left++;
		}
		//找到两个要交换的元素后,进行交换
		if(left < right){
			let temp = arr[left];
			arr[left] = arr[right];
			arr[right] = temp;
		}
	}

	//left==right找到基准元素的位置后赋值
	let temp = arr[left];
	arr[left] = pivot;
	arr[index] = temp;
	return left;
}

七、计数排序

计数排序

//计数排序基础版
function countSort(arr){
	//1.得到序列的最大值
	let max = arr[0];
	for(let i=0; i<arr.length; i++){
		if(arr[i] > max){
			max = arr[i];
		}
	}

	//创建数组,最大值为9,那么数组下标要到9,共10的数组长度
	var countArray = new Array(max+1);
	//数组赋值,不赋值均为undefined
	for(let i=0; i<countArray.length; i++){
		countArray[i] = 0;
	}
	//遍历原数组,并在统计数组中统计
	for(let i=0; i<arr.length; i++){
		countArray[arr[i]]++;
	}

	//遍历统计数组
	let index = 0;
	let sortedArray = new Array(arr.length);
	for(let i=0; i<countArray.length; i++){
		for(let j=0; j<countArray[i]; j++){
			sortedArray[index++] = i;
		}
	}
	return sortedArray;
}


//利用最大最小数设置偏移量:改良版计数排序
function countSort(arr){
	//1.找到最大值与最小值
	let min = arr[0], max = arr[0];
	for(let i=0; i<arr.length; i++){
		if(arr[i] > max){
			max = arr[i];
		}
		if(arr[i] < min){
			min = arr[i];
		}
	}
	//2.创建一个统计数组
	let countArray = new Array(max - min + 1);
	for(let i=0; i<countArray.length; i++){
		countArray[i] = 0;
	}

	//3.遍历原数组并统计  95  94  93  92
	for(let i=0; i<arr.length; i++){
		countArray[arr[i] - min]++;
	}

	//4.遍历统计数组赋值给新数组
	let index = 0;
	let sortedArray = new Array(arr.length);
	for(let i=0; i<countArray.length; i++){
		for(let j=0; j<countArray[i]; j++){
			//实际值为最小值加偏移量
			sortedArray[index++] = min + i;
		}
	}

	return sortedArray;
}


//稳定的计数排序
function countSort(arr){
	//1.找到最大最小值
	let max = arr[0], min = arr[0];
	for(let i=0; i<arr.length; i++){
		if(arr[i] > max){
			max = arr[i];
		}
		if(arr[i] < min){
			min = arr[i];
		}
	}

	//2.创建统计数组
	let countArray = new Array(max - min + 1);
	for(let i=0; i<countArray.length; i++){
		countArray[i] = 0;
	}

	//3.遍历原数组并统计
	for(let i=0; i<arr.length; i++){
		countArray[arr[i] - min]++;
	}

	//4.优化统计数组:从第二个元素开始,每个元素都加上前面所有元素的值
	//				 优化的统计数组每个元素的值,代表下标所对应的数在sortedArray中最大位置
	let sum = 0;
	for(let i=0; i<countArray.length; i++){
		sum += countArray[i];
		countArray[i] = sum;
	}

	//5.倒序遍历原始数列,从统计数组中找到自己的正确位置,赋值到结果数组
	let sortedArray = new Array(arr.length);
	for(let i=arr.length-1; i>=0; i--){
		sortedArray[countArray[arr[i] - min] - 1] = arr[i];
		countArray[arr[i] - min]--;
	}
	return sortedArray;
}
var arr = [66,55,87,48,79,12,14,45,46,65,35,25,84,30,79,84,96,99,63,53,80];
arr = countSort(arr);
console.log(arr);

八、希尔排序

function shellSort(arr){
	let len = arr.length;
	let cur_num;
	//增量从len/2开始,然后逐步缩减,直到增量为1
	for(let gap=Math.floor(len/2); gap>0; gap=Math.floor(gap/2)){	
		//从第gap个数,逐个对每个数所在组进行插入排序
		for(let i=gap; i<len; i++){
			let j = i;			//让j做游标,重置游标
			cur_num = arr[i];	//记录当前数字
			while(j-gap >= 0 && arr[j-gap] > cur_num){		//这个while似乎可以改成if
				arr[j] = arr[j-gap];	
				j = j - gap;
			}
			arr[j] = cur_num;
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值