冒泡排序、选择排序、快速排序、插入排序、堆排序、归并排序-JS

冒泡排序

遍历数组,比当前元素小时交换位置,当遇到本轮中的最大元素之后,后面的交换就不会变化
每次循环就能得到本轮循环中的最大元素

function findMAx(arr) {
    var n = arr.length - 1;
    //设置flg标记 序列是否有序
    //只要序列有序 flag等于上一个循环的flag=true,不会进入if语句,那么flag=false,退出for循环
    for (var flag = false; flag = !flag; n--) {
        for (var i = 1; i <= n; i++) {
            if (arr[i - 1] > arr[i]) {
                //交换
                console.log(arr[i-1],arr[i]);
                //js中数组存储是引用类型
                swap(arr,i - 1, i);
                flag = false;
            }
        }

    }
    return arr;
}
function swap(arr,i, j) {
    var t = arr[i];
    arr[i]=arr[j];
   	arr[j]=t;
}
var arr = [1, 3, 4, 2, 1, 4, 6];
findMAx(arr);
console.log(arr);

选择排序

每次选择数组中最小的元素,放在已排序的内容的后面,继续遍历后面的内容。

function select(arr){
	if(!arr) return;
	for(var i=0;i<arr.length;i++){
	//将当前遍历到的元素作为最小值,在遍历数组后续元素的时候,遇到更小的元素,交换位置
		var min=arr[i];
		for(var j=i;j<arr.length;j++){
			if(arr[j]<min){ 
				swap(arr,i,j);
				min=j;
			}
		}
	}
	return arr;
}

快速排序:

找到一个基准值pivot,在[lo,hi]之间找到它的合适位置

  • 小于该基准值 [lo,pivot-1]
  • 等于该基准值 pivot
  • 大于该基准值 [pivot+1,hi]
    一般取 pivot为lo
function quickSort(arr,lo,hi){
	if(hi<=lo) return;
	//两指针分别从数组的两端进行遍历
	var partition=sort(arr,lo,hi);
	quickSort(arr,lo,partition-1);
	quickSort(arr,partition+1,hi);
}
function sort(arr,lo,hi){
	var v=arr[lo];
	var i=lo,j=hi+1;
	if(!arr) return;
	while(true){
		//定义两个执政 i左指针从左向右扫描
		while(arr[++i]<v) if(i==hi) break;
		//右指针从右向左执行
		while(arr[--j]>v) if(j==lo) break;
		// 当两个指针相遇 
		if(i>=j) break;
		//左指针大于v 右指针小于v交换两个的位置 使得 v左端的值小于等于v v右端的值大于等于v
		swap(arr,i,j);
	}
	//最终找到基准值的合适位置
	swap(arr,lo,j);
	//返回找到的位置
	return j;
}
function sortEnd(arr){
	quickSort(arr,0,arr.length-1);
	return arr;
}
sortEnd(arr);
console.log(arr);

插入排序

将当前的元素,放到当前遍历区间的合适位置
比如:
当前遍历到a[i]
遍历a[i-1] a[i-2] …a[0] 将a[i]根绝大小放到合适的位置

//插入排序
function insertSort(arr){
	if(!arr) return;
	for(var i=1;i<=arr.length-1;i++){
		for(var j=i;j>=0;j--){
			if(arr[j]<arr[j-1]){
				swap(arr,j,j-1);
			}
		}
	}
	return arr;
}
insertSort(arr);
console.log(arr);

堆排序:

先构造堆,使堆有序,在构造大顶堆

堆有序:一个二叉树的节点大于等于它的子节点
当前节点k,父节点k/2向下取整,两个子节点 2*k2*k+1(是从1开始算到N)
但是数组中,一般是从下标为0的索引开始

某个节点比它的父节点大,上浮调整优先级
节点比子节点中较大者小,需要下沉调整位置

function sink(arr, k, N) {
    //节点k下沉
    while (2 * k + 1 <= N) {
        var j = 2 * k+1;
        if (j < N && arr[j] < arr[j + 1]) j++;
        if (arr[k] >arr[j]) break;
        swap(arr, k, j);
        k = j;
    }
}

//堆排序
function heapSort(arr) {
    var N = arr.length - 1;
    //堆有序
    for (var i = parseInt(N / 2); i >= 0; i--) {
        sink(arr, i, N);
        console.log(arr);
    }
    //将堆顶元素和最后的元素交换位置 将数组的范围缩小1(堆顶元素是最大的)
    while (N > 0) {
        swap(arr, 0, N--);
        sink(arr, 0, N);
    }
    return arr;
}
console.log(heapSort(arr));

归并排序

原地归并排序:将mid左右两端的区间[lo,mid]和[mid+1,hi]排列成有序

  • 自顶向下使用递归,将数组区间不断的划分成更小的区间,直到该区间有序
  • 自底向上使用循环迭代,将数组的区间以2个宽度开始原地归并排序,循环迭代2倍增长遍历区间的长度

将数组复制一份,数组的区间[lo,mid][mid+1,hi]是有序的,需要然和并之后的数组也是有序,使用自底向上的归并排序或自顶向下的排序

//原地归并
function merge(arr,lo,mid,hi){
	var i=lo,j=mid+1;
	//只复制一层就可以了
	var arrx=arr.slice(0);
	// console.log(arrx);
	for(var k=lo;k<=hi;k++){
		//当左边元素用完 
		if(i>mid){ 
			arr[k]=arrx[j++] ;
			// console.log('左边:'+arr,arrx);
		}
			//右边元素用完
		else if(j>hi) {
			arr[k]=arrx[i++];
			// console.log('右边:'+arr,arrx);
		}
		//当右边 比 左边大 将小值 复制到左边
		else if(arrx[i]>arrx[j]) {
			arr[k]=arrx[j++];
			// console.log('小:'+arr,arrx);
		}
		//当左边大是 将大值 复制到右边
		else {
			arr[k]=arrx[i++];
			// console.log('大:'+arr,arrx);
		}
	}
	return arr;
}

  • 自顶向下归并排序
//自顶向下使用递归,将数组划分成不重叠的子问题
function fromTtB(arr){
	sort(arr,0,arr.length-1);
	return arr;
}
function sort(arr,lo,hi){
	//递归基
	if(hi<=lo) return;
	var mid=lo+parseInt((hi-li)/2);
	sort(arr,lo,mid);
	sort(arr,mid+1,hi);
	merge(arr,lo,mid,hi);
}
  • 自底向上归并排序
function fromBtT(arr){
	var N=arr.length;
	//sz表示区间的长度
	for(var sz=1;sz<N;sz+=sz){
		for(var lo=0;lo<N-sz;lo+=sz+sz){
		//原地归并 当循环到最后时 ,区间的宽度可能比2sz短,因此区最终剩余的宽度
			merge(arr,lo,lo+sz-1,Math.min(lo+sz+sz-1,N-1));
		}
	}
	return arr;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值