排序-1-冒泡排序
前言
旨在
在对dx和dy这类无穷小量的研究中,《微积分的历程》中指出
牛顿是这种动态方法的倡导者。
诚然,学习微积分的过程充满了形同“割之弥细,所失弥少”的思考。不仅如此,牛顿的弦截法和牛顿二项展开式充满了递归思想,而这种过程用动态形式展现最好不过。如果非要说我们有什么理念的话,那么我们一切旨在用简单和谐的动态过程描述算法。我先承诺会对弦截法和牛顿二项展开式进行描述。最后,用Python和C++描述。(如果Python有时间的话)。
冒泡排序(Bubble Sort)
我们先介绍冒泡排序。冒泡排序因为每次都从底端把最大或最小的数依次比较送至顶端(为了更适合体现泡泡的上升,我们一般都会把数组倒放或竖排)形同冒泡,因此得名为冒泡排序。
这是一个非常知名的排序,仅仅因为名字好听。但也因为它的趣味性,非常适合入门。
我对冒泡排序的理解是,从小处看它是每每一次比较两个数,然后交换,从大处看,它每遍历一次,就会让一个最大的数放在最后面。因此最简单的做法就是遍历n-1遍,我们在这里的做法就是直接遍历n-1次。(说遍历有点不妥,但不影响我们认为是每走一趟,即排在最后已经排好序的元素不需要比较)。
这是冒泡排序的一个例子
我们输入一个数组,数组里有五个数[5 1 4 2 8],我们对这五个数进行从小到大的排序。
第一次遍历
(5 1 4 2 8) → (1 5 4 2 8) swap, since 5 > 1
(1 5 4 2 8) → (1 4 5 2 8) swap, since 5 > 4
(1 4 5 2 8) → (1 4 2 5 8) swap, since 5 > 2
(1 4 2 5 8) → (1 4 2 5 8)
第二次遍历
(1 4 2 5 8) → (1 4 2 5 8)
(1 4 2 5 8) → (1 2 4 5 8) swap, since 4 > 2
(1 2 4 5 8) → (1 2 4 5 8)
第三次遍历
(1 2 4 5 8) → (1 2 4 5 8)
(1 2 4 5 8) → (1 2 4 5 8)
这一圈遍历完以后,没有交换发生,说明数组已经排好序了(Sorted)。但是我的代码没有进行优化(即判断交换次数为0时,跳出循环)。因此会有第四次遍历。这让本来效率不高的冒泡排序更慢了。捂脸笑: )
第四次遍历
(1 2 4 5 8) → (1 2 4 5 8)
冒泡排序的复杂度
第一次循环 1 n-1 次比较
第二次循环 2 n-2 次比较
第三次循环 .... .... 次比较
第N-1次循环 n 1 次比较
比较次数之和 (n-1)+(n-2)+····+2+1=n(n-1)/2
(简书要是支持Mathjax就好了!)
时间复杂度:
Ο(N²)
这是冒泡排序的动态演示
这是冒泡排序的动态图。
冒泡排序-2.gif
C++代码实现
//输入5个数,对这5个数进行冒泡排序。
#include <iostream>
using namespace std;
int main()
{
int array[5];
for(int i = 0; i < 5; i++)
{
cin>>array[i];
}
for(int i = 0; i < 4; i++)//因为是5个数,所以只需比较4次。
{
for(int j = 0; j < 4-i; j++)//每次都从第一个数开始,每次把最大的数放在最后一位
{
int t;
if(array[j] > array[j+1])//如果前面的数大于后面的数,交换之。
{
t = array[j];
array[j] = array[j+1];//t是交换两数的空油瓶。
array[j+1] = t;
}
}
}
for(int i = 0; i < 5; i++)
{
cout<<array[i]<<' ';
}
return 0;
}
写在后面
关于冒泡排序
如Donald E. Knuth(1974年图灵奖获得者)所说:“冒泡排序除了它迷人的名字和导致了某些有趣的理论问题这一事实之外,似乎没有什么值得推荐的。”
当然,这个排序并不太难,但它蕴含了一种非常容易让人联想到的动态过程,并很容易让我们联想起更多非常巧妙和动态化的算法和数学思维,这也时时提醒我们学习本就是一件非常有趣的事。
参考文献
《啊哈!算法》
wikipedia
《微积分的历程》
使用工具
visualgo(参考http://visualgo.net)
GifCam