JavaScript实现冒泡排序及双向冒泡排序

前端经典算法题(一)之冒泡排序及双向冒泡排序

一、背景介绍

1、我在干嘛?

用JavaScript写一个冒泡排序算法

2、什么是冒泡排序?

啊这。。。怎么说呢?冒泡排序就是这个那个,冒泡嘛,你懂的,就是这样那样,然后再这样那样再排一下顺序~^-^就是冒泡排序
好吧,我认真说~
且看👀下图
在这里插入图片描述

就是每一轮,跟右边相邻的元素比较大小,比右边大,就跟右边换个位置

更新~
我在我的这篇博客里认真写了冒泡排序的思路,可以参考下
JavaScript实现冒泡排序、选择排序和插入排序

二、手写一个冒泡排序

其实只要理解了冒泡排序是啥意思,就知道这是一个双重for循环实现的,那就来吧~

(一)最简单最基本的冒泡排序

1、为了看清楚是怎么排序的,我用模版字符串给它打印出来

function bubble_sort1(array) {
  for(let i = 0; i < array.length - 1; i++) {
    for(let j = 0; j < array.length - i + 1; j++){
      if(array[j] > array[j+1]) {
        [array[j], array[j+1]] = [array[j+1], array[j]];
      }
      console.log(`${i}轮的第${j}次排完后的数组是酱紫滴${array}`);
    }
  }
  return array;
}

写个简单的数组测试一下

 let arr = [78, 1, 9, 100, 4, 2, 7, 37];
 console.log(bubble_sort1(arr));

我选了最后几行打印结果来看下,可以看出到最后几轮排序的时候,其实已经排好了顺序,但是它还要继续跑完循环,所以可以优化一下

......3轮的第5次排完后的数组是酱紫滴1,2,4,7,9,37,78,1004轮的第0次排完后的数组是酱紫滴1,2,4,7,9,37,78,1004轮的第1次排完后的数组是酱紫滴1,2,4,7,9,37,78,1004轮的第2次排完后的数组是酱紫滴1,2,4,7,9,37,78,1004轮的第3次排完后的数组是酱紫滴1,2,4,7,9,37,78,1004轮的第4次排完后的数组是酱紫滴1,2,4,7,9,37,78,1005轮的第0次排完后的数组是酱紫滴1,2,4,7,9,37,78,1005轮的第1次排完后的数组是酱紫滴1,2,4,7,9,37,78,1005轮的第2次排完后的数组是酱紫滴1,2,4,7,9,37,78,1005轮的第3次排完后的数组是酱紫滴1,2,4,7,9,37,78,1006轮的第0次排完后的数组是酱紫滴1,2,4,7,9,37,78,1006轮的第1次排完后的数组是酱紫滴1,2,4,7,9,37,78,1006轮的第2次排完后的数组是酱紫滴1,2,4,7,9,37,78,100

2、为了让我们知道后面优化到底有没有效果,所以在这里写了一个生成长度为n,且数组内的值也是0到n之间的随机整数的一个函数

function gernerate_array(n) {
  let array = [];
  for(let i = 0; i < n; n++){
    array.push(parseInt(Math.random() * n));
  }
  return array;
}

3、好的,我们加上时间戳来测试一下

        let arr = generateArr(50000);
        let timestamp1 = new Date().getTime();
        console.log(bubble_sort1(arr));
        let time_diff1 = new Date().getTime() - timestamp1;
        console.log(`第一种解法所用时间是${time_diff1}`)

结果是8470

(二)稍微优化一下的冒泡排序

1、现在稍微优化一下,思路是设置一个标志位,假如一轮下来,一次都没有交换过,说明已经排好了,那就不要再继续循环了

function bubble_sort2(array) {
  for(let i = 0; i < array.length - 1; i++) {
    /*默认是true,只要交换了一次就改变成false*/
    let flag = true;
    for(let j = 0; j < array.length - i + 1; j++) {
      if(array[j] > array[j+1]) {
        [array[j], array[j+1]] = [array[j+1], array[j]];
        flag = false;
      }
      console.log(`${i}轮的第${j}次排完后的数组是酱紫滴${array}`);
    }
    if(flag) {
      return array;
    }
  }
}

2、再用这个数组测试一下

 let arr = [78, 1, 9, 100, 4, 2, 7, 37];
 console.log(bubble_sort2(arr));

可以发现,从第4轮开始,一个数字都没有交换过,就不排了

3、那也来个时间戳测试一下性能

首先为了保证排的是同一个数组,来写一个数组的浅拷贝

        function lightClone(arr) {
            let res = []
            for(let i = 0; i < arr.length; i++) {
                res.push(arr[i]);
            }
            return res;
        }

好的来测试一下吧

        let arr = generateArr(50000);
        let arr2 = lightClone(arr);
        let timestamp1 = new Date().getTime();
        console.log(bubble_sort1(arr));
        let time_diff1 = new Date().getTime() - timestamp1;
        console.log(`第一种解法所用时间是${time_diff1}`)


        let timestamp2 = new Date().getTime();
        console.log(bubble_sort2(arr2));
        let time_diff2 = new Date().getTime() - timestamp2;
        console.log(`第二种解法所用时间是${time_diff2}`)

测试结果是

第一种解法所用时间是8689

第二种解法所用时间是8416

结论就是这个优化的也不是很大,主要是排好了顺序以后,减少无意义的循环

(三)双向冒泡排序

这个排序的思路是,先从左到右冒泡,排出一个最大值放在最右边,再从右到左冒泡,排出一个最小值放在最左边,再双向的往中间排。

这里也结合一下第二种解法中用到的标志位,减少无意义的循环

1、聪明的小盆友一看就知道我们需要两个指针,来编码实现吧

function bubble_sort3(array) {
  let left_index = 0;
  let right_index = array.length - 1;
  while (left_index < right_index) {
    let flag = true;
    /**先从左到右排**/
    for(let i = left_index; i < right_index; i++) {
      if(array[i] > array[i+1]) {
        [array[i], array[i+1]] = [array[i+1], array[i]];
        flag = false;
      }
    }
    right_index --;
    
    /**再从右到左排**/
    for(let i = right_index; i > left_index; i--) {
      if(array[i] < array[i-1]) {
        [array[i], array[i-1]] = [array[i-1], array[i]];
        flag = false;
      }
    }
    left_index ++;
    
    if(flag) {
      return array;
    }
  }
  return array;
}

2、好哒,来测试一下

        let arr = generateArr(50000);
        let arr2 = lightClone(arr);
        let arr3 = lightClone(arr);
        let timestamp1 = new Date().getTime();
        let sort_array1 = bubble_sort1(arr);
        console.log(sort_array1);
        let time_diff1 = new Date().getTime() - timestamp1;
        console.log(`第一种解法所用时间是${time_diff1}`)


        let timestamp2 = new Date().getTime();
        let sort_array2 = bubble_sort2(arr2);
        console.log(sort_array2);
        let time_diff2 = new Date().getTime() - timestamp2;
        console.log(`第二种解法所用时间是${time_diff2}`)

        let timestamp3 = new Date().getTime();
        let sort_array3 = bubble_sort3(arr3);
        console.log(sort_array3);
        let time_diff3 = new Date().getTime() - timestamp3;
        console.log(`第三种解法所用时间是${time_diff3}`)

测试结果

第一种解法所用时间是8451

第二种解法所用时间是8254

第三种解法所用时间是3858

好啦,可以看出双向冒泡排序比前两种明显快些~不过三种都还是O(n^2)哦

如果稀饭本篇博客就点个赞关注一下吧~

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值