请各位读者添加一下作者的微信公众号,以后有新的文章,将在微信公众号直接推送给各位,非常感谢。
0.前言
冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。
它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。
走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
这个算法的名字由来是因为越大的元素会经由交换慢慢“浮”到数列的顶端,故名。
正如百度百科中的所说,我们的冒泡排序是一种非常基础的一种算法,虽然在日常的工作中的使用的情况较少,但是由于其入门简单,逻辑清楚,还是非常适合初学者作为一个基础算法的入门,所以我们今天就一起来看一看,冒泡排序到底是怎么回事。
下面引用一下知乎用户可可的话术。
想想有一群泡泡
其中一个泡泡跑到一个泡小妹说,小妹小妹你过来咱俩比比谁大,小妹说哇你好大,于是他跑到了泡小妹前面,又跟前面的一个泡大哥说,大哥,咱俩比比谁大呗。泡大哥看了他一眼他就老实了。这就是内层的for,那个泡泡跟每个人都比一次。
话说那个泡泡刚老实下来,另一个泡泡又开始跟别人比谁大了,这就是外层的for,每个泡泡都会做一次跟其他泡泡比个没完的事。
注意,以下代码部分由 JS 代码进行展示。
1.如何实现排序
既然我们想要进行排序,那么我们首先必须要有一个基础的数组,然而这个数组的情况可能会存在很多种,这里我们暂时只讨论最复杂的情况。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
</body>
<script type="text/javascript">
// 声明一个最糟糕情况的数组
var arr = [9,8,7,6,5,4,3,2,1];
</script>
</html>
注意,我在这里声明了一个非常糟糕的数组,也就是说,数组中的每一个内容都需要进行排序。
既然我们有了这么一个基础的数组,我们就可以正式开始对我们的内容进行排序了。
根据冒泡排序的思想,我们每一次循环,都将数组中最大的那个数字,放在数组的最后。
这样就可以保证我们的数组中,每次循环中的最大的那个都在后面,这样全部循环一次之后,我们的内容也就全部排序完毕了。
具体实现可以参考下面的图片。
第一次循环的时候,将数组中最大的那个内容放在程序的最后面。
这是我们第一次交换数组中内容,那么我们交换了几次呢?
我们总共交换了 8 次。
因为倒数第二次的时候,我们的 1 和 9 就已经排序完毕了,而最后的数字 9 不需要我们再交换一次,所以最后交换次数是 8 次。
而第二次交换呢?
我们同样需要将数组中最大的哪一个数字挪动到数组的最后一位,这个时候,我们需要挪动几次呢?
我们的交换次数相比于上面的情况再次减少一次,现在总共挪动了 7 次。
以此类推,我们可以想象出来,挪动的次数应该如同下面这张图一样。
我们的数组长度为 9。
我们外层的循环数,第一次将数组中最大的一位数字挪动到最后面,第二次挪动第二大的数字,第三次第三大数字,……,直到我们最后将所有的内容全部挪动完毕。
那么我们可以得出一个结论,我们需要挪动的次数是 数组的长度 - 1 次。
也就是说,我们可以去使用一个循环。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
</body>
<script type="text/javascript">
var arr = [9,8,7,6,5,4,3,2,1];
// 外层控制的循环的次数,看我这里需要循环几次
for(var i = 0; i < arr.length - 1; i++){
document.write('<br>');
}
</script>
</html>
我们知道了我们这个数组需要循环几次,那么我们现在怎么控制我们需要在内部需要挪动几次呢?
这时候我们就要使用到内部的一层循环了。
我们可以在我们内层的循环中去控制我们的程序中间需要挪动几次。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
</body>
<script type="text/javascript">
var arr = [9,8,7,6,5,4,3,2,1];
// 外层控制的循环的次数,看我这里需要循环几次
for(var i = 0; i < arr.length - 1; i++){
// 内层控制数组内的循环次数
for(var j = 0; j < arr.length -i -1; j++){
document.write(arr + '<br>');
}
document.write('<br>');
}
</script>
</html>
这时候我们就已经将我们的数组中每一个元素都能依次查找到了,可是我们的冒泡循环不是为了进行排序么?
这时候我们需要将大的数字挪动到后面。
那么我们该怎么做呢?
我们需要将两个元素进行交换,那么怎么交换呢?
我们可以再次声明一个变量,这样将两个数字进行交换了。
// 进行内容的交换
if(arr[j] > arr[j + 1]){
var temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
这时候我们将之前的所有的内容进行合并,我们可以通过双重循环,将前后的数字和在它后面的数字进行交换。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
</body>
<script type="text/javascript">
var arr = [9,8,7,6,5,4,3,2,1];
// 外层控制的循环的次数,看我这里需要循环几次
for(var i = 0; i < arr.length - 1; 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;
}
document.write(arr + '<br>');
}
document.write('<br>');
}
</script>
</html>
这样当我们循环结束之后,我们的数字也就正好全部替换完成了。
2.后续
其实我们现在表示的,是冒泡排序中最糟糕的情况,每一个数字都需要进行交换,但是我们日常工作中可能不是所有的数字都需要进行排列。
有一部分的数字已经是全部排序好的,这时候我们不需要完全进行排序。
那该怎么办呢?
其实我们可以去定义一个变量,专门用于记录当前这个循环是否进行了循环,如果当前内层循环中,一次交换也没有发生,那么是不是就证明我们这个序列已经排序完毕了呢?
这样我们就可以去判断我们的变量,去看看我们的循环是否可以结束。
今天时间有限,就不去书写具体的代码了,大家可以在网上简单搜索一下,冒泡排序优化,自己试着去看看,怎么去将这个东西进行优化吧!~
网友评论