js实现堆 大根堆排序 小根堆排序

本文介绍了如何使用JavaScript实现堆排序,包括构造最大堆和最小堆的过程,并通过具体示例展示了从无序数组到有序数组的转换。通过不断调整堆结构,确保每次取出的都是当前堆的最大值或最小值,从而达到排序的目的。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先我的得到的是一个无序数组 , 要先将其构造成最大堆 , 再用堆排序得到有序的数组
无序的数组 : num = [1, 6, 12, 4, 5, 7, 8, 8, 9, 10, 0]
构造最大堆 : heap = [12, 10, 8, 9, 6, 7, 1, 8, 4, 5, 0]
使用堆排序 : num = [0, 1, 4, 5, 6, 7, 8, 8, 9, 10, 12]

构造最大堆的实现方法: 使父节点不断下沉 , 找到比父节点大的子节点 , 交换它们的位置 , 直到到达叶节点( 没有子节点 )
在一个二叉堆中: 父节点: i 左孩子: 2*i+1 右孩子: 2*i+2

//调整最大堆 arr数组 , i 是每次调整的父节点  , len 是目前堆的大小
let downAdjust = (arr, i, len) => {
    //用左孩子来判断终止条件,里面再判断有没有右孩子
    //如果用右孩子判断的话,不确定结束的时候还有没有左孩子
    let leftchild = 2 * i + 1
    while (leftchild < len) {
        //判断是否有右孩子以及右孩子的大小
        if (leftchild+1 < len && arr[leftchild + 1] > arr[leftchild])
            leftchild++
        //父节点大直接跳出
        if (arr[i] >= arr[leftchild])
        break
        //交换节点
        [arr[i], arr[leftchild]] = [arr[leftchild], arr[i]]
        //使父节点变成他交换的子节点
        i = leftchild
        //左孩子也进行相应的变换
        leftchild = 2 * i + 1
    }
}

实现最大堆排序

创建堆的同时 就把堆变成最大堆
我们的目的是把无序的数组 , 变成有序的 , 每次把最大的元素从堆顶交换到堆尾部的时候 , 我们都重新构造最大堆, 重新构造之后的堆 堆顶又是剩下的最大的元素 , 一直循环交换我们就可以得到有序的数组了

//创造堆 , 进行sort
let heapSort = (arr)=>{
    //把这个堆构建成最大堆. i代表的是父节点 , 显然从length-1开始是没有子节点的 
    //从有子节点的父节点开始构造堆 , 也就是i = (arr.length-1-1)/2  >>是除以二的意思
    for(let i = (arr.length-2)>>1;i>=0;i--){
        downAdjust(arr,i,arr.length)
    }
    console.log(arr);

    //循环删除替换arr中最大元素到尾部
    for(let i= arr.length-1;i>0;i--){
    		//我们要手动交换堆顶和堆尾的数据
        [arr[0],arr[i]] = [arr[i],arr[0]]
        //替换之后调整堆
        downAdjust(arr,0,i)
    }

}

全部代码

let num = [1, 6, 12, 4, 5, 7, 8, 8, 9, 10, 0]

//调整最大堆 arr数组 , i 是每次调整的父节点  , len 是目前堆的大小
let downAdjust = (arr, i, len) => {
    //用左孩子来判断终止条件,在里面判断有没有右孩子 如果用右孩子判断的话,不确定结束的时候还有没有左孩子
    let leftchild = 2 * i + 1
    while (leftchild < len) {

        //判断右孩子
        if (leftchild+1 < len && arr[leftchild + 1] > arr[leftchild])
            leftchild++
        //父节点大直接跳出
        if (arr[i] >= arr[leftchild])
        break
        //交换节点
        [arr[i], arr[leftchild]] = [arr[leftchild], arr[i]]
        //下标
        i = leftchild
        leftchild = 2 * i + 1
        

    }
}

//创造堆 , 进行sort
let heapSort = (arr)=>{
    //把这个堆构建成最大堆. i代表的是父节点 , 显然从length-1开始是没有子节点的 
    //从有子节点的父节点开始构造堆 , 也就是i = (arr.length-1-1)/2  >>是除以二的意思
    for(let i = (arr.length-2)>>1;i>=0;i--){
        downAdjust(arr,i,arr.length)
    }
    console.log(arr ,'最大堆');

    //循环删除替换arr中最大元素到尾部
    for(let i= arr.length-1;i>0;i--){
        [arr[0],arr[i]] = [arr[i],arr[0]]
        //替换之后调整堆
        downAdjust(arr,0,i)
    }

}

console.log(num , '无序数组');
heapSort(num)
console.log(num , '排序好的数组');

小根堆排序同理

//小根堆就是最小的在最上面 , 也是用父节点下沉 , 不过找的是比父节点还小的

let num = [1, 6, 0, 4, 10, 7, 1, 8, 9, 10, 0]

let downAdjust = (arr, i, len) => {

    let leftchild = 2 * i + 1
    while (leftchild < len) {
        //看看他的右孩子
        if (leftchild + 1 < len && arr[leftchild + 1] < arr[leftchild])
            leftchild++

        if (arr[i] <= arr[leftchild])
            break



        //交换两个最小的
        [arr[i], arr[leftchild]] = [arr[leftchild], arr[i]]


        //修改父节点和子孩子
        i = leftchild
        leftchild = 2 * i + 1
    }
}

let heapSort = (arr) => {
    //创建小根堆
    for (let i = Math.floor((arr.length - 2)/ 2); i >= 0; i--) {
        downAdjust(arr, i, arr.length)
    }
    console.log(arr);

    //使用小根堆排序
    for (let i = arr.length-1; i >= 0; i--) {
        //这里我们还要手动交换
        [arr[i], arr[0]] = [arr[0], arr[i]]
        //每次都把最小的交换到第一个去
        downAdjust(arr, 0, i)
    }
}

console.log(num);
heapSort(num)
console.log(num);


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值