JS 排序算法

一,冒泡排序
1, 相邻之间相比较,左边比右边大的话,交换位置。
2,第一轮下来,已经把最大的值选出来,并排在最后位,这样剩下需排序的的数组减1,依次类推。

function sort(arr) {
    for(let i = 0, l = arr.length - 1; i < l; i++) {
        for(let j = 0; j < arr.length - i - 1; j++) {
            if (arr[j] > arr[j+1]) {
                var temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
    return arr
}

二,快速排序
1,找一个基准点(一般是中间数)
2,和基准值比较,比基准值小放leftList,比基准值大放rightList
3,递归执行上述操作,直到arr.length <= 1

function sort(arr) {
    if (arr.length <= 1) return arr
    let midIndex = Math.floor(arr.length/2)
    let midVal = arr[midIndex] // 基准值,一般取中间数
    arr.splice(midIndex, 1)

    let leftList = []
    let rightList = []

    for(let i = 0, l = arr.length; i < l; i++) {
        if (arr[i] < midVal) {
            leftList.push(arr[i])
        } else {
            rightList.push(arr[i])
        }
    }

    return sort(leftList).concat(midVal, sort(rightList))
}

三,选择排序
1,找到数组中最小值的索引
2,把最小值排到第一位来。以此类推

function sort(arr) {
    if (arr.length <= 1) return arr

    let minIndex
    for(let i = 0, l = arr.length - 1; i < l; i++) {
        minIndex = i
        for(let j = i + 1; j < arr.length; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j
            }
        }
        if (i !== minIndex) [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]]
    }
}

四,插入排序
类似我们打扑克牌,牌从左向右的排序,抽出一张牌插到合适的位置放。
1,抽出位置1的牌,与位置0比较,当位置0的牌比1大时, 先把0的值填入位置1。剩下0位置插入。
2,抽出位置2的牌,与前面位置1比较,当位置1比2大时,先把1的值填入2位置,位置1空出。往下一层比较,找到合适的位置。依次类推。

function sort(arr) {
  let perIndex, current
  for(let i = 1, l = arr.length; i < l; i++) {
    perIndex = i - 1
    current = arr[i] // 抽出的位置值,当前位置为i === perIndex+1
    while(perIndex >= 0 && arr[perIndex] > current){
      arr[perIndex + 1] = arr[perIndex]  // 先把位置1的值填入2位置,空出位置1
      perIndex--  // 往下一层,此时perIndex位置为0,假设arr[0] < current时,循环结束,所以位置1(perIndex+1)的值为current
    }
    arr[perIndex+1] = current
  }
  return arr;
}

五,希尔排序
1,按一定的间隔对数组进行分组,一般以数组长度一半 gap = length / 2 (ps:也可以是3,4,无强性要求)
(假如:数组长度为10的话gap = 10 / 2 = 5,也就是,位置0和5为一组,位置1和6位一组…,组里的值进行插入排序)
2,以gap的一半进行缩小 gap = gap / 2
(此时:gap = Math.floor(5 / 2) = 2 向下取整,也就是,位置0和位置2为一组,位置1和3为一组…,组里的值进行插入排序)
3,当gap === 1时,此时所有元素为一组,此时运行的就是我们一般的插入排序了。
这样处理的好处是:希尔排序的优化使得原本 O(n^2) 的时间复杂度一下降为 O(nlogn)

function sort(arr) {
  for(let gap = Math.floor(arr.length / 2); gap > 0; gap = Math.floor(gap / 2)) {  // 循环组递减
    // 内循环与插入排序写法一致,只是每次移动的步长为gap
    for(let i = gap; i < arr.length; i++) {
      let temp = arr[i]
      let j = i - gap;  // 例如 gap = 4, 则j = 0, 0 和4位置之间的比较
      for(j; j >= 0 && temp < arr[j]; j -= gap) {
        arr[j + gap] = arr[j]
      }
      arr[j + gap] = temp
    }
  }
  return arr;
}

六,归并排序
采用分治思想
1,先把数组从中间分开,
[5, 4, 8, 2, 1, 9, 7, 3, 6, 0]
[5, 4, 8, 2, 1] [9, 7, 3, 6, 0]
[5, 4, 8] [2, 1] [9, 7, 3] [6, 0]
[5, 4] [8] [2] [1] [9, 7] [3] [6] [0]
[5] [4] [9] [7]
2,分别比较合并
[4, 5]
[4, 5, 8] [1, 2]
[1, 2, 4, 5, 8]

function sort(arr) {
  if(arr.length < 2) return arr

  let mid = Math.floor(arr.length / 2),
      left = arr.slice(0, mid),
      right = arr.slice(mid)
      
  return merge(sort(left), sort(right))
}

function merge(left, right) {
  const result = []
  while(left.length && right.length) {
    if(left[0] <= right[0]){
      result.push(left.shift())  // 相当于result.push(left[0]);left.shift()
    } else {
      result.push(right.shift())
    }
  }
  
  while(left.length) result.push(left.shift())
  while(right.length) result.push(right.shift())

  return result
}

七,堆排序

1,构建堆,堆顶是最大的元素(子结点的键值或索引总是小于(或者大于)它的父节点)
2,把最大的元素交换到堆顶,然后把堆顶跟交换到数组后面,数组减1,依次重复。

// 构建最大堆
function buildHeap(arr) {
    for(let i = Math.floor(arr.length / 2); i >= 0; i--) {
        adjustHeap(arr, i, arr.length)
    }
}
function adjustHeap(arr, i, len) {
    let left = 2 * i + 1,
        right = 2 * i + 2,
        largest = i  // 最大值位置

    // 3个节点的交换,找出最大做顶节点
    if (left < len && arr[left] > arr[largest]) {
        largest = left
    }
    if (right < len && arr[right] > arr[largest]) {
        largest = right
    }

    // 顶节点发生了变化,交换位置
    if (largest != i) {
        swap(arr, i, largest)
        adjustHeap(arr, largest, len)
    }
}
// 交换位置
function swap(arr, i, j) {
    [arr[i], arr[j]] = [arr[j], arr[i]]
}
// 取值排序
function sort(arr) {
    buildHeap(arr)  // 构建堆
    for(let i = arr.length - 1; i > 0; i--) {
        swap(arr, 0, i)  // 堆顶0肯定是最大的元素,先排到后面,然后数组长减1
        adjustHeap(arr, 0, i)  // 数组长减1后,调整堆
    }
}

八,桶排序
采用分治思想(ps:把数组分成若干小份,排好每小份,在拼接起来)
1, 定义一个桶的大小(一个桶能装下几个值)
2,根据数组的长度,计算需要几个桶,每个桶都是小的数组,组成二维数组
3,往桶里放数据
4,每个桶的数组使用插入排序
5,把每个桶的数据拼接起来

/*
    arr = 待排序数组
    bucketSize = 桶的大小,bucketSize = 5 一个桶装5个数
*/
function sort(arr, bucketSize = 5) {
    if (arr.length < 2) return arr

    const buckets = createBucket(arr, bucketSize)
    return sortBuckets(buckets)
}
// 划分桶存二维数组
function createBucket(arr, bucketSize) {
    let minValue = arr[0]
    let maxValue = arr[0]
    for(let i = 1; i < arr.length; i++) {
        if (arr[i] < minValue) {
            minValue = arr[i]
        }
        if(arr[i] > maxValue) {
            maxValue = arr[i]
        }
    }
    // 桶个数
    let bucketCount = Math.ceil((maxValue - minValue)/bucketSize)

    // 创建二维数组来存储
    const buckets = []
    for(let i = 0; i <= bucketCount; i++) {
        buckets[i] = []
    }
    // 把数据放进桶
    for(let i = 0, l = arr.length; i < l; i++) {
        let buckerIndex = Math.floor((arr[i] - minValue) / bucketSize)
        buckets[buckerIndex].push(arr[i])
    }
    return buckets
}

function sortBuckets(buckets) {
    let sortArray = []
    for(let i = 0, l = buckets.length; i < l; i++) {
        if (buckets[i] != null) {
            let sorted = inserSort(buckets[i])
            sortArray = [...sortArray, ...sorted]
        }
    }
    return sortArray
}
// 插入排序
function inserSort(arr) {
    if (arr.length < 2) return arr
    for(let i = 0, l = arr.length; i < l; i++) {
        let key = arr[i]
        let j = i - 1
        while (j >=0&&arr[j] > key) {
            arr[j + 1] = arr[j]
            j--
        }
        arr[j + 1] = key
    }
    return arr
}

九,计数排序
1,找出最大和最小元素。
2,统计每个元素出现的次数,以元素的值为索引,次数为value。
3,对所有计数开始累加,从min开始,每一项和前一项相加(加起来最后一个的值是数组的长度,用于下一步值的填充)
4,反向填充目标数组,将每个元素i放在新数组的第C[i]项,每放一个元素,计数-1

function sort(arr) {
    let len = arr.length,
        bucket = [],
        min = arr[0],
        max = arr[0],
        newArr = []

    for(let i = 0; i < len; i++) {
        min = min <= arr[i] ? min : arr[i] // 找出最小值
        max = max >= arr[i] ? max : arr[i] // 找出最大值
        bucket[arr[i]] = bucket[arr[i]] ? bucket[arr[i]]+1 : 1 // 收集值为索引
    }

    // 对所有计数累加
    for(let j = min; j < max; j++) {
        bucket[j + 1] = (bucket[j + 1] || 0) + (bucket[j] || 0)
    }

    for(let k = len - 1; k >= 0; k--) {
        newArr[bucket[arr[k]] - 1] = arr[k]
        bucket[arr[k]]--
    }
// 也可以这样的填充
// for(let k = 0; k <= max; k++) {
//     while (bucket[k]-- > 0) {
//         newArr.push(k)
//     }
// }

    return newArr
}

十,基数排序
适用,例如当你的数很大,如手机号码,的排序
1, 先按排序个位数,以各位的值为key, 这个的值为value, 进行按各位的排序
2,排好个位数后,用排好的数组在按十位数排,以十位数的值为key, 这个值为value, 进行按十位的排序,依次类推

/*
arr = 待排序数组
max = 最大位数
*/

function sort(arr, max) {
    const buckets = []
    let unit = 10
    let base = 1
    for(let i = 0; i < max; i++, base *= 10, unit *= 10 ){
        //先排好个位,在排十位...
        for(let j = 0; j < arr.length; j++) {
            let index = Math.floor((arr[j]%unit) / base)  // 过滤出个位数,十位数,...

            if (buckets[index] == null) {
                buckets[index] = []
            }
            buckets[index].push(arr[j])
        }
        let pos = 0
        let value
        for(let j = 0, l = buckets.length; j < l; j++) {
            if (buckets[j] != null) {
                while ((value = buckets[j].shift()) != null) {
                    arr[pos++] = value
                }
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值