JS算法 | 选择排序

227 阅读3分钟

前言

此文衍生自《【JS算法】排序算法》,针对选择排序的稳定性进行补充讲解。排序算法的稳定性在《【JS算法】排序算法》已经进行讲解,此处不再重复。文中用 JavaScript 实现算法,讲述选择排序算法的基本实现,验证此算法的基本实现是不稳定的,同时扩展,如何实现稳定版的选择排序

基本实现

思路

  • 遍历数组中未排序的元素,找出最小(大)值,放在第一个位置
  • 重复第一步操作,直到所有元素均排序完毕

代码

// 算法的基本实现
var arraySort = function(arr){
    let min
    let temp
    for(let i = 0; i < arr.length - 1; i++){
        min = i;
                // 从未排序的数据中寻找最小值
        for(let j = i + 1; j < arr.length; j++){
            if(arr[min] > arr[j]){
                min = j
            }
        }
                // 将最小值放到数据的第一个位置
        if(min != i){
            temp = arr[i];
            arr[i] = arr[min]
            arr[min] = temp 
        }
    }
}

不稳定验证

对上面代码进行修改,对对象数组,基于 price 属性进行递增排序

  • 声明数组
// 数组
var arr = [
     {
        price: 11,
        value: 453
    },
    {
        price: 123,
        value: 456
    },
    {
        price: 12,
        value: 457
    },
    {
        price: 11,
        value: 459
    },
    {
        price: 10,
        value: 460
    }
]
  • 改造函数
// 代码第 8 行,原来比较自身,现在改为比较内部属性的 price
var arraySort = function(arr){
    let min
    let temp
    for(let i = 0; i < arr.length - 1; i++){
        min = i;
                // 从未排序的数据中寻找最小值
        for(let j = i + 1; j < arr.length; j++){
            if(arr[min].price > arr[j].price){
                min = j
            }
        }
                // 将最小值放到数据的第一个位置
        if(min != i){
            temp = arr[i];
            arr[i] = arr[min]
            arr[min] = temp 
        }
    }
}

arraySort(arr)
  • 打印结果
// 调用 arraySort 进行排序后,arr 打印出来的结果如下
// [
//          {
//        price: 10,
//        value: 460
//      },
//      {
//        price: 11, 
//        value: 459
//      },
//          {
//        price: 11, 
//        value: 453
//      },
//          {
//        price: 12, 
//        value: 457
//      },
//          {
//        price: 123,
//        value: 456
//      }
// ]
  • 从上面代码可看出, 排序前 {price: 11, value: 453}{price: 11, value: 459} 前面,排序后{price: 11, value: 453}{price: 11, value: 459} 后面,所以此实现是不稳定的

稳定实现

思路

  • 补充数组 minArray,使用首元素与 arr 中的元素进行比对时,如果当前元素与首元素相等,将 key 存储到 minArray
  • 寻找完毕如果 minArray 的长度大于 1,则证明有重复的元素
  • 将 arr 中在 minArray 存储了 key 且 key < min 的元素做逆时针移动,这样可以保证与首元素相等的元素的相对位置不变,同时用与 min 最接近的和首元素相等的元素代替首元素的位置,保证在与 min 替换后,与首元素相等的元素之间的相对位置依然不变
  • 最后执行原有步骤中的位置替换操作,然后清空 minArray,避免污染下一轮循环

代码

var arraySort = function(arr){
    let min
    let temp
    // 声明数组
    let minArray = []
    for(let i = 0; i < arr.length - 1; i++){
        min = i 
        // 存放第一个元素的 key
        minArray.push(i)
        for(let j = i + 1; j < arr.length; j++){
            if(arr[i].price === arr[j].price){
                    // 当第一个元素与当前元素相等时,存放当前元素的 key
                minArray.push(j)
            }
            if(arr[min].price > arr[j].price){
                min = j
            }
        }
        if(min != i){
            if(minArray.length > 1){
                                // 将元素做逆时针移动
                // 将 minArray 中存储的并且小于 min 的 key 对应 arr 中的元素逐个后移,然后将第一个被替换的元素存储,放置第一个
                for(let k = minArray.length - 1; k > 0; k--){
                    if(minArray[k] > min){
                        continue
                    }
                    // 如果 temp 为空 temp 就将当前的元素存放,这样就达到保留第一个元素的目的
                    if(temp === undefined){
                        temp = arr[minArray[k]]
                    }
                    // 将前面的元素逐个后移
                    arr[minArray[k]] = arr[minArray[k - 1]]
                }
                // 然后将 temp 赋值给最后一个
                arr[minArray[0]] = temp
            }
            // 执行完上面的操作后,再将最小的值与第一个值互换
            temp = arr[i]
            arr[i] = arr[min]
            arr[min] = temp 
        }
        minArray = []
    }
}

arraySort(arr)
// 调用 arraySort 进行排序后,arr 打印出来的结果如下
// [
//          {
//        price: 10,
//        value: 460
//      },
//      {
//        price: 11, 
//        value: 453
//      },
//          {
//        price: 11, 
//        value: 459
//      },
//          {
//        price: 12, 
//        value: 457
//      },
//          {
//        price: 123,
//        value: 456
//      }
// ]

总结

以上代码实现了选择排序的稳定版,通过消耗多余的资源来保证原有位置不被改变,可能并不是最优解,欢迎评论指导