左神 六大排序js实现

78 阅读2分钟

排序总结

冒泡排序

let arr = [1, 2, 5, 4, 8, 9, 0, 10, 43];
function maopao(arr) {
  // 外层循环i控制比较的轮数
  for (let i = 0; i < arr.length; i++) {
    // 里层循环控制每一轮比较的次数j,arr[i] 只用跟其余的len - i个元素比较
    for (let j = 1; j < arr.length - i; j++) {
      // 若前一个元素"大于"后一个元素,则两者交换位置
      if (arr[j - 1] > arr[j]) {
        temp = arr[j];
        arr[j] = arr[j - 1];
        arr[j - 1] = temp;
      }
    }
  }
  return arr;
}
console.log("maopao" + maopao(arr));
function bubblesort(arr) {
  let temp = null;
  let flag = 1;
  for (let i = 0; i < arr.length && flag === 1; i++) {
    flag = 0;
    for (let j = 0; j < arr.length - i; j++) {
      if (arr[j] > arr[j + 1]) {
        temp = arr[j + 1];
        arr[j + 1] = arr[j];
        arr[j] = temp;
        flag = 1;
      }
    }
  }
  return arr;
}
console.log("maopao:" + bubblesort(arr));

选择排序

function selectsort(arr) {
  if (arr == null || arr.length < 2) {
    return;
  }
  // 0 ~ N-1  找到最小值,在哪,放到0位置上
  // 1 ~ n-1  找到最小值,在哪,放到1 位置上
  // 2 ~ n-1  找到最小值,在哪,放到2 位置上
  for (let i = 0; i < arr.length - 1; i++) {
    let minIndex = i;
    for (let j = i + 1; j < arr.length; j++) {
      // i ~ N-1 上找最小值的下标
      minIndex = arr[j] < arr[minIndex] ? j : minIndex;
    }
    swap(arr, i, minIndex);
  }
  return arr;
}
function swap(arr, i, j) {
  temp = arr[i];
  arr[i] = arr[j];
  arr[j] = temp;
}
console.log("选择:" + selectsort(arr));
//插入排序

function insertionSort(arr) {
  if (arr == null || arr.length < 2) {
    return;
  }
  for (let i = 1; i < arr.length; i++) {
    for (let j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) {
      swap(arr, j, j + 1);
    }
  }
  return arr;
}
console.log("插入:" + insertionSort(arr));

快速排序

function partition(arr, l, r) {
  if (l > r) {
    return -1;
  }
  if (l == r) {
    return l;
  }
  let lessEqual = l - 1;
  let index = l;
  while (index < r) {
    if (arr[index] <= arr[r]) {
      swap(arr, index, ++lessEqual); //a[index]和小于等于区右边交换
    }
    index++;
  }
  swap(arr, ++lessEqual, r); //刚才r没动,现在交换小于等于区右边和r的位置
  return lessEqual;
}
function process1(arr, l, r) {
  if (l >= r) {
    return;
  }
  let m = partition(arr, l, r);
  process1(arr, l, m - 1);
  process1(arr, m + 1, r);
}

function quickSort1(arr) {
  if (arr == null || arr.length < 2) {
    return;
  }
  process1(arr, 0, arr.length - 1);
  return arr;
}

console.log("快排1:" + quickSort1(arr));

function netherlandsFlag(arr, l, r) {
  //以arr[r]做划分值
  if (l > r) {
    let ea = [-1, -1];
    return ea;
  }
  if (l == r) {
    let ea = [l, r];
    return ea;
  }
  let less = l - 1; //<区 右边界
  let more = r; //>区 左边界
  let index = l;
  while (index < more) {
    //当前位置,不能和>区的左边界撞上
    if (arr[index] == arr[r]) {
      //[i]==num,i++
      index++;
    } else if (arr[index] < arr[r]) {
      //[i]<num,[i]与<区的右一个交换,<区右扩,i++
      swap(arr, index++, ++less);
    } else {
      swap(arr, index, --more); //[i]>num,[i]与>区左一个交换,>区左扩,i(原地不动)
    }
  }
  swap(arr, more, r); //再把最后的r和大于区最左交换,r就和等于区相接了
  let ea = [less + 1, more]; //返回等于区域的左边界和右边界
  return ea;
}
function process3(arr, l, r) {
  if (l > r) {
    return;
  }
  swap(arr, l + Number.parseInt(Math.random() * (r - l + 1)), r); //这个任意数咋回事
  let euqalArea = netherlandsFlag(arr, l, r);
  process3(arr, l, euqalArea[0] - 1);
  process3(arr, euqalArea[1] + 1, r);
}

function quickSort3(arr) {
  if (arr == null || arr.length < 2) {
    return;
  }
  process3(arr, 0, arr.length - 1);
  return arr;
}
console.log("快排3:" + quickSort3(arr));

堆排序

function heapSort(arr) {
  if (arr == null || arr.length < 2) {
    return;
  }
  for (let i = arr.length - 1; i >= 0; i--) {
    //把数组调整成为大根堆
    heapify(arr, i, arr.length);
  }
  let heapSize = arr.length;
  swap(arr, 0, --heapSize); //把最大的那个值固定好
  //o(n*logn)
  while (heapSize > 0) {
    //开始调整成大根堆,然后不断的把堆顶调整到最后,就是有序
    heapify(arr, 0, heapSize);
    swap(arr, 0, --heapSize);
  }
  return arr;
}
function heapify(arr, index, heapSize) {
  let left = index * 2 + 1; //左孩子下标
  while (left < heapSize) {
    //下方还有孩子的时候
    //两个孩子中,谁的值大,把下标给largest
    //1.只有左孩子,left->largest
    //2.同时有左孩子和右孩子,右孩子的值小于等于左孩子的值,left->largest
    //3.同时有左右孩子,右大于左,right->largest
    let largest =
      left + 1 < heapSize && arr[left + 1] > arr[left] ? left + 1 : left;
    //父和较大的孩子之间,谁的值大,把下标给largest
    largest = arr[largest] > arr[index] ? largest : index;
    if (largest == index) {
      break;
    }
    swap(arr, largest, index);
    index = largest;
    left = index * 2 + 1;
  }
}
console.log("堆排序:" + heapSort(arr));

归并排序

function mergeSort1(arr) {
  if (arr == null || arr.length < 2) {
    return;
  }
  mergeProcess(arr, 0, arr.length - 1);
  return arr;
}
function mergeProcess(arr, l, r) {
  if (l == r) {
    return;
  }
  let mid = l + ((r - l) >> 1);
  mergeProcess(arr, l, mid);
  mergeProcess(arr, mid + 1, r);
  merge(arr, l, mid, r);
}
function merge(arr, l, m, r) {
  let help = [];
  help.length = r - l + 1;
  let i = 0;
  let p1 = l;
  let p2 = m + 1;
  while (p1 <= m && p2 <= r) {
    help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
  }
  //要么p1越界了,要么p2越界了
  while (p1 <= m) {
    help[i++] = arr[p1++];
  }
  while (p2 <= r) {
    help[i++] = arr[p2++];
  }
  for (i = 0; i < help.length; i++) {
    arr[l + i] = help[i];
  }
}
console.log("归并排序:" + mergeSort1(arr));
function mergeSort2(arr) {
  if (arr == null || arr.length < 2) {
    return;
  }
  let n = arr.length;
  //步长
  let mergeSize = 1;
  while (mergeSize < n) {
    //当前左组的第一个位置
    let l = 0;
    while (l < n) {
      let m = l + mergeSize - 1; //当前左组是从l 到 m的
      if (m >= n) {//这个组直接越界了
        break;
      }
      let r = Math.min(m + mergeSize, n - 1); //算右组的右边界,如果数不够,就到n-1
      merge(arr, l, m, r);
      l = r + 1; //下一组的左组开始,是r+1
    }
    //防止溢出
    if (mergeSize > n / 2) {
      break;
    }
    mergeSize <<= 1; //左移一位,就是*2
  }
  return arr;
}
console.log("归并排序非递归:" + mergeSort2(arr));