Javascript排序

81 阅读3分钟

一、冒泡排序

// 每次筛选出最大的一个数放在第i位,循环arr.length-1次
function bubble(arr) {
  for(let i = arr.length - 1; i > 0; i--) {
    for(let j = 0; j < i; j++) {
      if(arr[j] > arr[j+1]) {
        [arr[j], arr[j+1]] = [arr[j+1], arr[j]]
      }
    }
    console.log(arr);
    //[ 3, 6, 2, 10 ]
    //[ 3, 2, 6, 10 ]
    //[ 2, 3, 6, 10 ]
  }
  return arr
}

var arr = [3, 10, 6, 2]
console.log(bubble(arr)); // [ 2, 3, 6, 10 ]

二、插入排序

// 每次循环确保前i个数有序排列
function insertion(arr) {
  for(let i = 1; i < arr.length; i++) {
    let j = i
    while( j > 0 && arr[j] < arr[j -1]) {
      [arr[j], arr[j-1]] = [arr[j-1], arr[j]]
      j--
    }
    console.log(arr);
    //[ 3, 10, 6, 2 ]
    //[ 3, 6, 10, 2 ]
    //[ 2, 3, 6, 10 ]
  }
  return arr
}

var arr = [3, 10, 6, 2]
console.log(insertion(arr)); // [ 2, 3, 6, 10 ]

三、选择排序

// 每次确定最小的minIndex和当前i换位
function selection(arr) {
  for(let i = 0; i < arr.length - 1; i++) {
    let minIndex = i
    for(let j = i+1; j < arr.length; j++) {
      minIndex = arr[j] < arr[minIndex] ? j : minIndex
    }
    [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]]
    console.log(arr)
    //[ 2, 10, 6, 3 ]
    //[ 2, 3, 6, 10 ]
    //[ 2, 3, 6, 10 ]
  }
  return arr
}

var arr = [3, 10, 6, 2]
console.log(selection(arr)); // [ 2, 3, 6, 10 ]

四、归并排序

// 将数组递归平分->排序->合并
function mergeSort(arr) {
  let n = arr.length
  if(n == 1) return arr
  // 计算中间位置
  const middle = Math.floor(n/2)
  // 对左边数组进行归并排序
  const left = mergeSort(arr.slice(0, middle))
  // 对右边数组进行归并排序
  const right = mergeSort(arr.slice(middle))
  // 合并两个排序好的数组
  console.log(left, right);
  // [ 3 ] [ 10 ]
  // [ 6 ] [ 2 ]
  // [ 3, 10 ] [ 2, 6 ]
  return merge(left,right)
}
function merge(left, right) {
  // 定义指针变量 分别指向两个数组的开头
  let i = 0,j = 0
  // 定义一空数组 用来存放合并好的数组
  const result = []
  while(i < left.length && j < right.length) {
    if(left[i] < right[j]) {
      result.push(left[i++]) // 先push再i++
    } else {
      result.push(right[j++])
    }
  }
  while(i < left.length) {
    result.push(left[i++])
  }
  while(j < right.length) {
    result.push(right[j++])
  }
  return result
}

var arr = [3, 10, 6, 2]
console.log(mergeSort(arr)); // [ 2, 3, 6, 10 ]

五、快速排序

  • 利用新数组
// 取一个值,数组中比这个大的放到left,比它小的放到right
// 递归分割数组,合并数组
function quickSort(arr) {
  if(arr.length <= 1) return arr
  let mid = Math.floor(arr.length/2),
   midNum = arr.splice(mid, 1)[0]
  let left = [],right = []
  arr.forEach(item => {
    item > midNum ? right.push(item) : left.push(item)
  })
  console.log(left, midNum, right);
  return quickSort(left).concat(midNum).concat(quickSort(right))
}

var arr = [3, 10, 6, 2]
console.log(quickSort(arr)); // [ 2, 3, 6, 10 ]
  • 在原数组交换位置
// 相对于第一种节省了空间
function quickSort2(arr, left, right) {
  if(left < right) {
    let i = left, 
      j = right,
      empty = arr[left]
    while(i < j) {
      while(arr[j] > empty && i < j) {
        j--
      }
      arr[i] = arr[j]
      console.log('1',arr);
      while(arr[i] < empty && i < j) {
        i++
      }
      arr[j] = arr[i]
      console.log('2',arr);
      console.log(i, j);
    }
    arr[i] = empty
    quickSort2(arr,left,i)
    quickSort2(arr,i+1,right)
    return arr
  } else {
    return
  }
}

var arr = [3, 10, 6, 2]
console.log(quickSort2(arr, 0, 3)); 
1 [ 2, 10, 6, 2 ]
2 [ 2, 10, 6, 10 ]
1 3
1 [ 2, 10, 6, 10 ]
2 [ 2, 10, 6, 10 ]
1 1
1 [ 2, 3, 6, 10 ]
2 [ 2, 3, 6, 10 ]
0 0
1 [ 2, 3, 6, 10 ]
2 [ 2, 3, 6, 10 ]
2 2
[ 2, 3, 6, 10 ]

六、希尔排序

// 希尔排序不断减小比较的区间
// 当len为10时 gap 5 2 1
function shellSort(arr) {
  let len = arr.length
  let gap = Math.floor(len / 2) // 5
  while(gap > 0) {
    for(let i = gap; i < len; i++) {
      // gap为5时 i为5 6 7 8 9 -> j-gap为 0 1 2 3 4
      // gap为2时 i为2 3 5 6 7 8 9 -> j-gap 为 0 1 2 3 4 5 6 7
      // gap为1时 i为1 2 3 4 ...9 -> j-gap 为 0 1 2 ... 8
      let j = i
      while(j - gap >= 0 && arr[j] < arr[j-gap]) {
        [arr[j],arr[j-gap]] = [arr[j-gap],arr[j]]
        j -= gap 
        // 举例:当gap为2时, arr[9] < arr[7] -> arr[9]和arr[7]换位后 arr[7] 接着和arr[5]比...
      }
    }
    gap = Math.floor(gap/2) // 2、1、0
  }
  return arr
}

var arr = [3, 10, 6, 2, 7, 4, 1, 9, 5, 8]
console.log(shellSort(arr)); // [ 1, 2, 3, 4,  5, 6, 7, 8, 9, 10]

七、堆排序

function heapSort(arr) {
  buildMaxHeap(arr) // 建造大根堆
  let len = arr.length - 1
  for(let i = len; i > 0; i--) { // 将堆顶与后面进行位置交换
    [arr[0], arr[i]] = [arr[i], arr[0]]
    maxHeapify(arr, 0, len)
    len--
  }
  return arr
}
function buildMaxHeap(arr) {
  const len = arr.length
  for(let i = Math.floor(len/2) - 1; i>=0; i--) {
    maxHeapify(arr, i ,len)
  }
}
function maxHeapify(arr, index, size) {
  const left = 2*index + 1
  const right = 2*index + 2
  let largest = index
  if(left < size && arr[left] > arr[largest]) {
    largest = left
  }
  if(right < size && arr[right] > arr[largest]) {
    largest = right
  }
  if(largest != index) {
    [arr[index], arr[largest]] = [arr[largest], arr[index]]
    maxHeapify(arr, largest, size)
  }
}

var arr = [3, 10, 6, 2, 7, 4, 1, 9, 5, 8]
console.log(heapSort(arr)); // [ 1, 2, 3, 4,  5, 6, 7, 8, 9, 10]