跳至主要內容

手写常用排序算法

yyshino大约 4 分钟FrontEnd算法JS算法

冒泡排序

在未排序区域中,从前向后不断对比相邻数据,将较大值不断向后移动,直至移动到未排序区域的最后一位。

    const arr = [2, 44, 1, 0, -22, 56, -78];
    // arr.sort((a,b)=>a-b)
    function bubbleSort(arr){
        let tmp;
        for(let i=arr.length; i>0; i--){// 较大的arr[j]会冒泡到arr的尾部
            for(let j=0; j<i-1; j++){
                if(arr[j]>arr[j+1]){// 前一个元素比或一个大,则向后冒泡(交换)
                    tmp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = tmp;
                }
            }
        }
        return arr;
    }
    console.log(bubbleSort(arr));// [-78, -22, 0, 1, 2, 44, 56]

选择排序

遍历未排序区域,通过对比相邻数据,记录较小值的下标,每遍历一遍就能找出未排序区域中最小的数据,将记录的未排序区域的最小值与未排序区域的第一个元素交换位置,该位为有序,未排序区域长度减一,直至完成排序。

const arr = [2, 44, 1, 0, -22, 56, -78];
function selectionSort(arr){
	for(let i = 0;i<arr.length;i++){
		let minIndex = i; // 假设arr[i]为最小元素(即默认就是递增)
		let tmp;
		for(let j = i+1;j<arr.length;j++){ 
			if(arr[j]< arr[minIndex]){// 如果arr[j]比arr[minIndex]还小
				minIndex = j;// 更新最小元素的下标
			}
		}
		// 交换arr[i]和arr[minIndex]
		tmp = arr[i];
		arr[i] = arr[minIndex]
		arr[minIndex] = tmp
	}
}

插入排序

将第一个数据视为已排序区域,取第一个未排序区域中的数据,从它前一个位置依次向前寻找,直至找到第一个小于等于它的数据,或超出数组范围(已排序区域中没有比它小的值),则将它从未排序区域移除,插入到第一个小于等于它的位置后,或第一位。直至全部排序结束。

function insetSort(arr){
	for(let i = 1; i< arr.length;i++){
        let index = i;
        let temp = arr[i]
        while(index > 0 && arr[index - 1] > temp){
            index--
        }
        arr.splice(i,1);
        arr.splice(index,0,temp);
    }
}

归并排序

通过递归将数组不断一分为二,直至每个数组只有一个元素,这时数组即为有序的。在合并时因为两个数组都是有序的,只需比较两个有序数组中的第一个元素,将较小的放入合并后的数组中,即可合并出一个有序数组。

function mergeSort(arr){
	if(arr.length < 2){
		return arr
	}
	
	let mid = Math.floor(arr.length/2);
	let leftArr = arr.slice(0,mid);
	let rightAr  = arr.slice(mid);
	return merge(mergeSort(leftArr,mergeSort(rightArr)));
}

function merge(leftArr,rightArr){
    let res = [];
    while(leftArr.length > 0 && rightArr.length > 0){
		if(leftArr[0] < rightArr[0]){
            res.push(leftArr.shift())
        }else {
            res.push(rightArr.shift())
        }
    }
    
    if(leftArr.length !== 0){
        res.push(...leftArr)
    }
    
    if(rightArr.length !== 0){
        res.push(...rightArr)
    }
    return res
}

快速排序

从未排序区域中取一个值视为基准值(通常取最中间位置的值),将剩余数据中,小于该值的数据放入leftArr中,将大于等于该值的数据放入rightArr中,此时基准值即为有序。再不断对leftArr和rightArr分别重复该步骤,直至数组中只有一个元素(数组中只有一个元素时为有序数组),将leftArr、基准值、rightArr按顺序合并成一个数组,该数组即为有序。

function shellSort(arr) {

    for(let gap = Math.floor(arr.length / 2); gap > 0; gap = Math.floor(gap / 2)) {
        for(let i = gap; i < arr.length; i ++) {
            let index = i;
            let temp = arr[i];
            while(index > 0 && arr[index - gap] > temp) {
                index -=gap;
            }
            arr.splice(i, 1);
            arr.splice(index, 0, temp);
        }

    }

}

参考

https://juejin.cn/post/7127636022996762654

https://www.cnblogs.com/pangqianjin/p/14998643.html#:~:text=JavaScript%E6%89%8B%E5%86%99%E5%87%A0%E7%A7%8D%E5%B8%B8%E8%A7%81%E7%9A%84%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95%EF%BC%9A%E5%86%92%E6%B3%A1%E3%80%81%E9%80%89%E6%8B%A9%E3%80%81%E6%8F%92%E5%85%A5%E3%80%81%E5%B8%8C%E5%B0%94%E3%80%81%E5%BD%92%E5%B9%B6%E3%80%81%E5%BF%AB%E6%8E%92%201%20%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F%202%20%E9%80%89%E6%8B%A9%E6%8E%92%E5%BA%8F%203,%E6%8F%92%E5%85%A5%E6%8E%92%E5%BA%8F%204%20%E5%B8%8C%E5%B0%94%E6%8E%92%E5%BA%8F%205%20%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F%206%20%E5%BF%AB%E9%80%9F%E6%8E%92%E5%BA%8F