javascript堆排序

in 算法 with 0 comment

二叉堆

二叉堆是一颗完全二叉树,实际操作中是把二叉堆放到数组中顺序存储的,而不是像二叉树一样链式存储

二叉堆添加元素,上浮操作

function upAdjust1(arr) {
      //找到新添加的元素的父节点在数组中的下标
      let childIndex = arr.length - 1
      let parentIndex = parseInt((childIndex - 1) / 2)
      while(childIndex) {
        if(arr[parentIndex] > arr[childIndex]) {
          let temp = arr[parentIndex]
          arr[parentIndex] = arr[childIndex]
          arr[childIndex] = temp
        }else{
          break
        }
        childIndex = parentIndex
        parentIndex = parseInt((childIndex - 1) / 2)
       //console.log(parentIndex)
      }
    }
    //升级版,不是两两交换
    function upAdjust2(arr) {
      //而是把添加的元素找到合适的位置
      let childIndex = arr.length - 1
      let parentIndex = parseInt((childIndex - 1) / 2)
      let element = arr[childIndex]
      while (childIndex) {
        if(arr[parentIndex] > arr[childIndex]) {
          arr[childIndex] = arr[parentIndex]
          arr[parentIndex] = element
        }else{
          break
        }
        childIndex = parentIndex
        parentIndex = parseInt((childIndex - 1) / 2)
      }
      //console.log(childIndex)
      
    }
    //优化一版,不要随便在循环中使用break, continue这些
    function upAdjust3(arr) {
      //而是把添加的元素找到合适的位置
      let childIndex = arr.length - 1
      let parentIndex = parseInt((childIndex - 1) / 2)
      let element = arr[childIndex]
      while (childIndex && arr[parentIndex] > arr[childIndex]) {
        arr[childIndex] = arr[parentIndex]
        arr[parentIndex] = element
        childIndex = parentIndex
        parentIndex = parseInt((childIndex - 1) / 2)
      }  
    }
    //大招终极
    function upAdjust(arr) {
      //找到位置把要添加的元素放进去
      let childIndex = arr.length - 1
      let parentIndex = parseInt((childIndex - 1) / 2)
      let element = arr[childIndex]
      while (childIndex && arr[parentIndex] > element) {
        arr[childIndex] = arr[parentIndex]
        childIndex = parentIndex
        parentIndex = parseInt((childIndex - 1) / 2)
      }
      arr[childIndex] = element
    }

二叉堆删除堆顶元素,下沉操作


//删除堆顶元素,进行单一节点下调(堆已有序), 元素交换,自己写的第一版
    function downAdjust2(arr, parentIndex) {
      //把最后一个叶子节点赋值给删除的索引处
      arr[parentIndex] = arr[arr.length - 1]; //数组长度 - 1
      arr.splice(arr.length - 1, 1); 
      while (2 * parentIndex + 2 <= arr.length) {
        let rightChildIndex = 2 * parentIndex + 2;
        if (rightChildIndex >= arr.length) {
          let temp = arr[parentIndex];
          arr[parentIndex] = arr[rightChildIndex - 1];
          arr[rightChildIndex - 1] = temp;
          parentIndex = rightChildIndex - 1;
        } else {
          if (arr[rightChildIndex - 1] > arr[rightChildIndex]) {
            let temp = arr[parentIndex];
            arr[parentIndex] = arr[rightChildIndex];
            arr[rightChildIndex] = temp;
            parentIndex = rightChildIndex;
          } else {
            let temp = arr[parentIndex];
            arr[parentIndex] = arr[rightChildIndex - 1];
            arr[rightChildIndex - 1] = temp;
            parentIndex = rightChildIndex - 1;
          }
        }
      }
    }


//删除堆顶元素,进行单一节点下调(堆已有序),非元素交换, 自己写的第二版
    function downAdjust1(arr, parentIndex) {
      //把最后一个叶子节点赋值给删除的索引处
      let element = arr[arr.length - 1];
      //数组长度 - 1
      arr.splice(arr.length - 1, 1);
      //let len = arr.length;
      let rightChildIndex = 2 * parentIndex + 2;
      while (rightChildIndex <= arr.length) {
        if (rightChildIndex === arr.length) {
          arr[parentIndex] = arr[rightChildIndex - 1];
          parentIndex = rightChildIndex - 1;
        } else {
          if (arr[rightChildIndex - 1] > arr[rightChildIndex]) {
            arr[parentIndex] = arr[rightChildIndex];
            parentIndex = rightChildIndex;
          } else {
            arr[parentIndex] = arr[rightChildIndex - 1];
            parentIndex = rightChildIndex - 1;
          }
        }
        rightChildIndex = 2 * parentIndex + 2;
        //console.log(parentIndex)
      }
      //找到位置了
      arr[parentIndex] = element;
    }

    

构造二叉堆(无序完全二叉树 ---> 二叉堆)

//写的第一版,按正常逻辑,异常麻烦


//只是做节点下沉操作,数组长度不动它,用作构造二叉堆,进行堆排序操作,此时整个二叉堆是无序的
  function downAdjust3(arr, parentIndex) {
    let element = arr[parentIndex];
    let rightChildIndex = 2 * parentIndex + 2;
    while (rightChildIndex <= arr.length) {
      if (rightChildIndex === arr.length) {
        if (element > arr[rightChildIndex - 1]) {
          arr[parentIndex] = arr[rightChildIndex - 1]; 
        }else{
          break
        }
        parentIndex = rightChildIndex - 1;
      } else {
        if (arr[rightChildIndex - 1] > arr[rightChildIndex]) {
          if (element > arr[rightChildIndex]) {
            arr[parentIndex] = arr[rightChildIndex];
          }else{
            break
          }
          parentIndex = rightChildIndex;
        } else {
          if (element > arr[rightChildIndex - 1]) {
            arr[parentIndex] = arr[rightChildIndex - 1];
          }else{
            break
          }
          parentIndex = rightChildIndex - 1;
        }
      }
      rightChildIndex = 2 * parentIndex + 2;
    }
    //找到位置了
    arr[parentIndex] = element;
  }


//只是做节点下沉操作,数组长度不动它, 用作构造二叉堆,进行堆排序操作 第二版
  function downAdjust(arr, parentIndex) {
    let element = arr[parentIndex];
    let childIndex = 2 * parentIndex + 1;
    while (childIndex < arr.length) {
      //这里当 childIndex + 1  = arr.length时,arr[arr.length] == undefined
      let tempIndex
      // if(arr[childIndex + 1]) {
      //   tempIndex = arr[childIndex] < arr[childIndex + 1] ? childIndex : ++childIndex;
      // } else {
      //   tempIndex = childIndex
      // }
      arr[childIndex + 1] ? (tempIndex = arr[childIndex] < arr[childIndex + 1] ? childIndex : ++childIndex) : (tempIndex = childIndex)
      if(element > arr[tempIndex]) {
        arr[parentIndex] = arr[tempIndex];
        parentIndex = tempIndex;
        childIndex = 2 * parentIndex + 1;
      }else{
        break
      }
    }
    //找到位置了
    arr[parentIndex] = element;
  }

//放大招
//最小堆,堆顶删除,重新生成最小堆
function downAdjust(arr, parentIndex) {
    let element = arr[parentIndex];
    let childIndex = 2 * parentIndex + 1;
    while (childIndex < arr.length) {
      //这里当 childIndex + 1  = arr.length时,arr[arr.length] == undefined
      //高级,体现水平
      if((childIndex + 1 < arr.length) && (arr[childIndex] > arr[childIndex + 1])) {
        childIndex ++;
      }
      if(element > arr[childIndex]) {
        arr[parentIndex] = arr[childIndex];
        parentIndex = childIndex;
        childIndex = 2 * parentIndex + 1;
      }else{
        break
      }
    }
    //找到位置了
    arr[parentIndex] = element;
  }

  //最大堆,堆顶删除,重新生成最大堆
  function downAdjustBig(arr, parentIndex) {
    let element = arr[parentIndex];
    let childIndex = 2 * parentIndex + 1;
    while (childIndex < arr.length) {
      //这里当 childIndex + 1  = arr.length时,arr[arr.length] == undefined
      //高级,体现水平
      if((childIndex + 1 < arr.length) && (arr[childIndex] < arr[childIndex + 1])) {
        childIndex ++;
      }
      if(element < arr[childIndex]) {
        arr[parentIndex] = arr[childIndex];
        parentIndex = childIndex;
        childIndex = 2 * parentIndex + 1;
      }else{
        break
      }
    }
    //找到位置了
    arr[parentIndex] = element;
  }

构造堆,自己的思路

自己实现了两版的排序,不过都需要重新new一个数组,空间复杂度一下上去了

//为了从小到大排序,构建一个最大堆, 如果构造最小堆,循环也可以正向来
function buildHeap(arr) {
    for (let i = parseInt((arr.length - 1) / 2); i >= 0; i--) {
      downAdjustBig(arr, i);
    }
    //return arr;
  }

//自己实现的版本一,简洁,因为每一轮都buildHeap,这样做可能效率低下,每一轮其实只需要downAdjust

  function heapSort1(arr){
    let temparr = []
    let len = arr.length
    for(let i = 0; i < len; i++) {
      buildHeap(arr)
      temparr.unshift(arr[0])
      arr.splice(0, 1)
    }
    console.log(temparr)
  }

// 自己实现的版本二,调用时需要传数组长度, 使用downAdjust
function heapSort(arr, len){
    //① 从小到大排序,首先构造成最大堆
    //② 依次删除堆顶,执行downAdjust操作产生新的堆顶
    buildHeap(arr)
    let temparr = []
    //删除堆顶元素
    for(let i = 0; i < len; i++) {
      temparr.unshift(arr[0])
      //单向赋值即可
      arr[0] = arr[len - i - 1]
      //new 新堆,新堆是原堆长度--
      arr.splice(len - i - 1, i + 1)
      downAdjustBig(arr, 0)
    }
    console.log(temparr)
  }

构造堆,不重新new一个数组,降低空间复杂度

思路是执行downAdjust调整时,指定downAdjust的调整范围


//构建一个最大堆,并指定比较范围

  function downAdjustBig1(arr, parentIndex, len) {
    let element = arr[parentIndex];
    let childIndex = 2 * parentIndex + 1;
    while (childIndex < len) {
      //这里当 childIndex + 1  = arr.length时,arr[arr.length] == undefined
      //高级,体现水平
      if((childIndex + 1 < len) && (arr[childIndex] < arr[childIndex + 1])) {
        childIndex ++;
      }
      if(element < arr[childIndex]) {
        arr[parentIndex] = arr[childIndex];
        parentIndex = childIndex;
        childIndex = 2 * parentIndex + 1;
      }else{
        break
      }
    }
    //找到位置了
    arr[parentIndex] = element;
  }


function heapSort(arr){
    buildHeap(arr)
    for(let i = 0; i < arr.length; i++) {
      //上来直接交换元素
      let temp = arr[0]
      arr[0] = arr[arr.length - i - 1]
      arr[arr.length - i - 1] = temp
      //在指定范围内进行调整
      downAdjustBig1(arr, 0, arr.length - i - 1)
    }
  }
评论已关闭.