用JS实现常见的排序算法(冒泡,选择,插入,希尔,快速排序等)

一、简单排序

1.冒泡排序

冒泡排序是一种最简单粗暴的排序算法,它的排序方式跟它的名字一样,一个个数据往上冒出来。
主要的思路其实就是从最左边开始,依次比较相邻两个元素的大小,若左边的数大于右边的数就进行交换,这样把所有的相邻元素都比较一遍以后,最右边的数就是其中最大的数了。

紧接着又继续从最左边开始,依次比较各个相邻元素,并判断是否需要交换位置,但与第一遍不同的是,最右边的数不需要进行比较,因为它已经是最大的了。因此第二遍比较完后从右往左数第二个数是其中第二大的数。

以此类推,就能将数据按从小到大的顺序排好了

var arr = [28,4,10,6,21]
for(var i = 0; i < arr.length; i++) {  //比较的轮数
    for(var 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
        }
    }
}

2.选择排序

每遍历一次就选出最小的,然后放入已排好的末尾

选择排序跟冒泡排序非常类似,唯一的区别就是选择排序每次遍历时,将各个元素比较,将最大值或最小值的索引存放在一个变量中,全部比较完了以后,再将该索引上的元素进行就交换。

简单来说就是选择排序是每次遍历交换一次,而冒泡排序每次遍历需要交换多次,因此选择排序一般来说是要比冒泡排序效率高一点的。

var arr = [28,4,10,6,21]
// 1. 设定遍历的范围
for(var i = 0; i < arr.length; i++) {
    // 2. 先将遍历的起始索引设为最小值的索引
    var min = i
    // 3. 从索引为min的后一个值开始遍历全部元素
    for(var j = min; j < arr.length; j++) {
        // 3.1 将每个遍历到的元素与arr[min]比较
        if(arr[min] > arr[j]) {
            min = j
        }
    }
    // 4. 将得到的最小值的索引min上的元素与我们初始遍历的位置上的元素交换
    var temp = min
    min = i
    i = temp
}

3.插入排序

插入排序是一种将指定元素与某个有序区域元素比较并交换位置的排序算法。

var arr = [28,4,10,6,21]
// 1. 从索引为1的元素开始向后遍历数组
for(var i = 0; i < arr.length; i++) {
    // 2. 取出有序区域右边第一个元素
    var temp = arr[i]
    var j = i
    // 3. 从右往左将有序区域内的元素与temp比较
    while(arr[j-1] > temp && j > 0) {
        arr[j] = arr[j-1]
        j--
    }
    // 4. 将temp插入到合适的位置
    arr[j] = temp
}

二、高级排序

1.希尔排序

希尔排序是插入排序的改进版本,弥补了插入排序在某些情况下的缺点

var arr = [9,10,7,5,11,20,14,2]
//获取初始的间隔长度
var interval = arr.length / 2
//不断地缩小间隔的大小,进行分组插入排序
while(interval >= 1) {
    //从 arr[interval] 开始往后遍历,将遍历到的数据与其小组进行插入排序
    for(var i = interval; i < arr.length; i++) {
        var temp = arr[i]
        var j = i
        while(arr[j-interval] > arr[j] && j-interval >=0) {
            arr[j] = arr[j-interval]
            j = j - interval
        }
        //将temp插入到合适的位置
        arr[j] = temp
    }
    //缩小间隔
    interval = Math.floor(interval / 2)
}

2.快速排序

快速排序效率很高,也是面试中经常会被问到的,而且可能会让大家当场手写,所以一定要掌握它的核心思想
快速排序也用到了分而治之的思想,它的实现思路非常得有意思:

  1. 先选一个元素作为基点pivot
  2. 将其余元素中所有比pivot小的值放到pivot的左边;将所有比pivot大的值放到pivot的右边
  3. 然后分别对pivot左边的所有元素、pivot右边的所有元素从步骤1开始排序依次,直到所有元素完整有序
function quickSort(arr) {
   // 两个数据进行交换
   function exchange(v1,v2) {
       var temp = arr[v1]
       arr[v1] = arr[v2]
       arr[v2] = temp
   }
   // 找到相对合适的元素放到数组索引为0的位置作为基点pivot
   function init(leftIndex,rightIndex) {
       var centerIndex = Math.floor((leftIndex+rightIndex) / 2)
        // 比较索引为left、center、right三个值的大小,从小到大排列
       if(arr[leftIndex] > arr[rightIndex]) exchange(leftIndex,rightIndex)
       if(arr[centerIndex] > arr[rightIndex]) exchange(centerIndex,rightIndex)
       if(arr[leftIndex] > arr[centerIndex]) exchange(leftIndex,centerIndex)
        // 判断数组长度是否大于3,若小于3,则数组已经排序好了,不需要做任何处理
       if(rightIndex - leftIndex > 2) exchange(leftIndex,centerIndex)
   }
   function sort(left,right) {
       init(left,right)
       // 若数组长度小于等于2,则不需要做任何操作了,因为init函数已经排序好了
       if(right - left <= 2) return
       // 创建指针i和j,分别指向left和right
       var i = left
       var j = right
       // 将该数组区域的第一个元素作为基点pivot
       var pivot = arr[i]
       // 不断让指针i和j寻找合适的值填坑,直到两个指针重合
       while(j > i) {
           // 指针j不断向左找小于pivot的值,但指针j不能找到指针i的左边
           while(arr[j] > pivot && j > i) {
               j--
           }
            // 将找到的小于pivot的值填到指针i所指向的坑中
           arr[i] = arr[j]
           // 指针i不断向右找大于pivot的值,但指针i不能找到指针j的右边
           while(arr[i] < pivot && j > i) {
               i++
           }
           // 将找到的大于pivot的值填到指针j所指向的坑中
           arr[j] = arr[i]
       }
       // 将pivot填到指针i和指针j共同指向的坑中
       arr[i] = pivot
       // 对此时pivot的左边所有元素进行快排
       sort(left,i-1)
       // 对此时pivot的右边所有元素进行快排
       sort(i+1,right)
   }
   sort(0,arr.length-1)
   return arr
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值