一.简述
上篇总结了一下常用的排序算法,排序算法总结,这篇文章将详细介绍冒泡排序算法。
冒泡排序法(Bubble Sort)是由观察水中冒泡的变化启发而来,需要遍历几次数组,在每次遍历的过程中,比较连续相邻的元素,如果相邻的两个元素是降序,则将他们俩的值互换,如果是升序则保持不变,然后再继续比较下一个相邻元素。由于较小的值像“气泡”一样会逐渐浮起来,较大的值会慢慢沉下底部,所以将这种排序技术形象的称为“冒泡排序”或者“下沉排序”。
二. 原理
原理其实上面已经有所说明,具体就是:
(1)比较相邻的元素,如果第一个比第二个大,就交换他们两个;
(3)针对所有的元素重复以上的步骤;
现在为了更加清楚的说明原理,我们举个例子:
有8个数:
3,9,2,7,5,0,8,10
从左到右依次比较相邻元素:
(1)先比较第一对元素(3,9),因为这两个数本来就是先大后小的顺序,所以不需要进行交换;
(2)然后比较第二对元素(9,2),因为 9 大于 2,所以需要交换两个数,8个数的次序暂时为:3,2,9,7,5,0,8,10;
(3)接着计较第三对数(9,7),因为 9 大于 7 ,所以交换俩数,8个数的次序暂时变为:
3,2,7,9,5,0,8,10;
(4)继续比较第四对数(9,5),因为9 大于 5, 所以交换,8个数的次序暂时变为:
3,2,7,5,9,0,8,10;
(5)继续比较第五对数(9,0),因为9 大于 0, 所以交换,8个数的次序暂时变为:
3,2,7,5,0,9,8,10;
(6)继续比较第六对数(9,8),因为9 大于 8, 所以交换,8个数的次序暂时变为:
3,2,7,5,0,8,9,10;
(6)继续比较第七对数(9,10),因为9 小于 10, 所以交换,8个数的次序暂时变为:
3,2,7,5,0,8,9,10;
经过一次遍历后,910放在的最后。其实冒泡排序经过第一次遍历后,最后一个元素就是数组中最大的元素,第二次遍历后,倒数第二个元素就是数组中第二大的数,而相应的比它们小的数则会慢慢向数组前面移动。
上面是完成一轮遍历的过程,紧接着进行第二轮遍历,第三轮…,因为在第k轮遍历时,不需要考虑最后k-1个元素,因为它们已经排好序了,所以8个数一共进行7轮遍历才可以完成冒泡排序。
三.分析
1. 时间复杂度分析(以n个数为例)
最好情况下:
冒泡排序算法只进行一轮遍历就能确定数组已经排好序,不需要进行下一轮遍历,由于第一次遍历的比较次数为 n-1,所以在最好情况下,冒泡排序的时间复杂度为O(n)。
最坏情况下:
这种情况下冒泡排序算法需要进行 n-1 轮遍历才可以排序完成,
第一次需要 n-1 次比较;
第二次需要 n-2 次比较;
…
第n-2 次需要 2 次比较;
第n-1 次需要 1 次比较;
因此,比较的总数为:
(n-1)+ (n-2) + … + 2 + 1
= ((n-1)*n)/2
= ((n^2)-n)/2
= O(n^2)
最坏情况下,冒泡排序的时间复杂度为 O(n^2)
2. 空间复杂度
需要一临时变量来交换两个数,所以空间复杂度为O(1)
3. 稳定性
冒泡排序排序之前两个数如果相等,这两个数在排序的过程中是不会去调换位置的,所以是稳定的。
四. 代码
C++代码:
#include <iostream>
#include <iomanip>
using namespace std;
//待排序元素个数
#define N 8
//函数声明
void Show(int *data, int n);
void BubbleSort(int *data, int n);
//主函数
int main()
{
//待排序数据
int data[N]={3,9,2,7,5,0,8,10};
cout<<"***************排序前的数据为:**************";
Show(data, N);
BubbleSort(data, N);
cout<<"***************排序后的数据为:**************";
Show(data, N);
system("pause");
}
//冒泡排序
void BubbleSort(int *data, int n)
{ int temp;
//第i轮冒泡扫描,共进行n-1轮
for(int i=n-1; i>0; i--)
{
for(int j=0; j<i; j++)
{
//若前面数大于后面数,则进行交换
if(data[j] > data[j+1])
{
temp = data[j];
data[j] = data[j+1];
data[j+1] = temp;
}
}
cout << "第" << N-i <<"轮遍历后的排序结果为:\t";
Show(data, N);
}
}
//输出数组
void Show(int *data, int n)
{
for(int i=0; i<n; i++)
{
cout << setw(3) << data[i];
}
cout << endl;
}
运行结果:
改进:
我们发现如果在某轮遍历中没有发生任何元素的交换,说明所有的元素都已经排序好了,这种情况下我们是没有必要进行下一次遍历的,如上图运行结果,第6轮其实和第五轮排序后的结果是一样的,第六轮其实根本就没有交换元素,所以在接下来的第七轮我们其实没必要再继续排序了,所以上面的排序算法实现是可以改进的,改进代码如下:
#include <iostream>
#include <iomanip>
using namespace std;
//待排序元素个数
#define N 8
void Show(int *data, int n);
void BubbleSort(int *data, int n);
//主函数
int main()
{
//待排序数据
int data[N]={3,9,2,7,5,0,8,10};
cout<<"***************排序前的数据为:**************" << endl;
Show(data, N);
BubbleSort(data, N);
cout<<"***************排序后的数据为:**************" << endl;
Show(data, N);
system("pause");
}
//冒泡排序
void BubbleSort(int *data, int n)
{
bool isNeedNext = true;
int temp;
//第i轮冒泡扫描,共进行n-1轮
for(int i=n-1; i>0 && isNeedNext; i--)
{
isNeedNext = false;
for(int j=0; j<i; j++)
{
//若前面数大于后面数,则进行交换
if(data[j] > data[j+1])
{
temp = data[j];
data[j] = data[j+1];
data[j+1] = temp;
isNeedNext = true;
}
}
cout << "第" <<" "<< N-i <<" "<<"轮遍历后的排序结果为:";
Show(data, N);
}
}
//输出数组
void Show(int *data, int n)
{
for(int i=0; i<n; i++)
{
cout << setw(3) << data[i];
}
cout << endl;
}
运行结果:
第七轮排序是没有进行的,因为第六轮后整个数据已经排序完成了。
如果错误,欢迎指正,谢谢!