JavaScript排序算法归纳总结

204 阅读1分钟
  • 插入排序:最普通的排序算法,从数组下标为1的元素开始遍历。拿到当前元素循环与前面的所有元素比较,如果当前元素小于前一位元素则交换位置,否则跳出循环。 动画展示如下图:

1.gif

代码如下:

function sort(array) {
    let arg = array.slice(0);  //复制元素避免污染原数组
    for (let i = 1; i < arg.length; i++) {
        let j = i
        while (j > 0) {
            if (arg[j] < arg[j - 1]) {
                let temp = arg[j]
                arg[j] = arg[j - 1]
                arg[j - 1] = temp
                j--
            } else {
                break
            }
        }
    }
    return arg;
}
  • 二分查找:前提需要该数组是有序的。1.先从有序数组的中间元素开始查找,如果与该元素相等则直接返回该索引,否则进行下一步。2.如果指定的元素大于或者小于中间元素,则在大于或小于的那一半区域内查找,重复第一步直到找到目标元素。找不到则返回-1 代码演示如下:
function sort(array, target) {
    let i = 0;
    let len = array.length - 1;
    let mid;
    while (i <= len) {
        mid = Math.floor((len + i) / 2)
        if (array[mid] == target) {
            return mid
        } else if (array[mid] < target) {
            i = mid + 1
        } else {
            len = mid - 1
        }
    }
    return -1
}
console.log(sort([10, 12, 14, 18, 19], 10))
  • 二分插入排序: 每次插入操作前,采用上文中二分查找的方式。查找插入的位置,然后再插入元素(先挪动后再插入) 如果不理解可以参考b站视频: www.bilibili.com/video/BV1iE…

代码如下:

function binaryInsertSort(arr) {
    var i, cur, left, right, mid;
    for (i = 1; i < arr.length; i++) {
        left = 0;
        right = i - 1;
        cur = arr[i];
        while (left <= right) {
            mid = Math.floor((left + right) / 2);
            if (cur < arr[mid]) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        arr.splice(left, 0, arr.splice(i, 1)[0]);
    }
    return arr;
}
binaryInsertSort([10, 12, 14, 18, 1])
  • 希尔排序 图形解释更加清楚如下:

1230971-20190610135909136-679000090.jpg

function shellSort(arr) {
    let len = arr.length;
    // gap 即为增量
    for (let gap = Math.floor(len / 2); gap > 0; gap = Math.floor(gap / 2)) {
        for (let i = gap; i < len; i++) {
            let j = i;
            let current = arr[i];
            while (j - gap >= 0 && current < arr[j - gap]) {
                arr[j] = arr[j - gap];
                j = j - gap;
            }
            arr[j] = current;
            console.log(arr)
        }
    }
}
shellSort([15, 4, 1, 32, 33, 5]);
  • 冒泡排序 1、比较相邻的两个元素,如果前一个比后一个大,则交换位置。 2、比较完第一轮的时候,最后一个元素是最大的元素。 3、这时候最后一个元素是最大的,所以最后一个元素就不需要参与比较大小。 代码如下:
function shellSort(arr) {
    for (let j = 0; j < arr.length - 1; j++) {
            for (let i = 0; i < arr.length - j - 1; i++) {//因为不需要对比最后一位
            if (arr[i] > arr[i + 1]) {
                let temp = arr[i]
                arr[i] = arr[i + 1]
                arr[i + 1] = temp

            }
        }
    }
    return arr
}
shellSort([15, 4, 1, 10, 33, 5]);
  • 选择排序 定义一个最小值minIndex初始化是第一个,循环遍历数组找到比minIndex小的调换位置,继续遍历i+1后面的元素
function shellSort(arr) {
    for (let i = 0; i < arr.length; i++) {
        let minIndex = i
        for (let j = i + 1; j < arr.length; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j
            }
        }
        [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]]

    }
    console.log(arr)

}
console.log(shellSort([15, 4, 1, 10, 33, 5]));
  • 归并排序 实现思路如下图(一直觉得不需要分治只需要合并,可能是代码不太好写所以分治) 1843694-20200313212249098-1952951076.png

js代码实现:

function mergeSort(arr) {
    let len = arr.length
    if (len < 2) {
        return arr
    }
    let middle = Math.floor(len / 2)
    //拆分成两个子数组
    let left = arr.slice(0, middle)
    let right = arr.slice(middle, len)
    //递归拆分
    let mergeSortLeft = mergeSort(left)
    let mergeSortRight = mergeSort(right)
    //合并
    return merge(mergeSortLeft, mergeSortRight)
}
const merge = (left, right) => {
    const result = [];

    while (left.length && right.length) {
        // 注意: 判断的条件是小于或等于,如果只是小于,那么排序将不稳定.
        if (left[0] <= right[0]) {
            result.push(left.shift()); //每次都要删除left或者right的第一个元素,将其加入result中
        } else {
            result.push(right.shift());
        }
    }
    //将剩下的元素加上
    while (left.length) result.push(left.shift());

    while (right.length) result.push(right.shift());

    return result;
};
console.log(mergeSort([15, 4, 15, 10, 33, 5]));
  • 快速排序 原理比较简单,取数组第一个元素为中间元素(理论上是任意元素都可以)。循环遍历数组,大于中间元素的放在中间元素的右边,小于等于中间元素的放在左边。重复以上步骤直到数组长度为0即可,代码如下。 此排序方法还有另外一种描述具体可以参考一下如下链接:www.bilibili.com/video/BV1at… js代码如下:
function sort(arr) {
    if (arr.length < 1) {
      return arr
    }
    let mid = arr.shift()
    let left = [],
      right = [];
    for (let i = 0; i < arr.length; i++) {
      if (arr[i] > mid) {
        right.push(arr[i])
      } else {
        left.push(arr[i])
      }
    }
    return sort(left).concat(mid, sort(right))
}
console.log(sort([5, 4, 11, 2, 1]));
  • 计数排序(非比较排序) 原理:首先获取数组的最大值,新建一个数组长度为最大值+1用0填充(称为统计数组)。遍历数组获得每个值的出现次数,然后遍历(长度为统计数组的长度)。嵌套循环统计次数大于0的(为了重复元素),添加到新数组即可。
function sort(arr) {
    let max = Math.max.apply(null, arr)
    let arg = new Array(max + 1).fill(0) //计数数组
    let array = [];
    for (let i = 0; i < arr.length; i++) {
      let idx = arr[i]
      arg[idx]++
    }
    for (let h = 0; h < max + 1; h++) {
      for (let k = arg[h]; k > 0; k--) {
        array.push(h);
      }
    }
    console.log(array)
}
sort([0, 5, 5, 5, 77, 1, 8, 7])