常见排序之冒泡排序
1.基本思想:
在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。
2.算法描述:
①每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。依次比较相邻的两个数,将小数放在前面,大数放在后面。
②首先比较第1个和第2个数,将小数放前,大数放后;然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。
③重复第一轮的步骤,直至全部排序完成
3.举例:
例1:
(1)要排序数组:[10,1,35,61,89,36,55]
(2)第一趟排序:
第一次排序:10和1比较,10大于1,交换位置 [1,10,35,61,89,36,55]
第二趟排序:10和35比较,10小于35,不交换位置 [1,10,35,61,89,36,55]
第三趟排序:35和61比较,35小于61,不交换位置 [1,10,35,61,89,36,55]
第四趟排序:61和89比较,61小于89,不交换位置 [1,10,35,61,89,36,55]
第五趟排序:89和36比较,89大于36,交换位置 [1,10,35,61,36,89,55]
第六趟排序:89和55比较,89大于55,交换位置 [1,10,35,61,36,55,89]
第一趟总共进行了六次比较,排序结果:[1,10,35,61,36,55,89]
(3)第二趟排序:
第一次排序:1和10比较,1小于10,不交换位置 1,10,35,61,36,55,89
第二次排序:10和35比较,10小于35,不交换位置 1,10,35,61,36,55,89
第三次排序:35和61比较,35小于61,不交换位置 1,10,35,61,36,55,89
第四次排序:61和36比较,61大于36,交换位置 1,10,35,36,61,55,89
第五次排序:61和55比较,61大于55,交换位置 1,10,35,36,55,61,89
第二趟总共进行了5次比较,排序结果:1,10,35,36,55,61,89
(4)第三趟排序:
1和10比较,1小于10,不交换位置 1,10,35,36,55,61,89
第二次排序:10和35比较,10小于35,不交换位置 1,10,35,36,55,61,89
第三次排序:35和36比较,35小于36,不交换位置 1,10,35,36,55,61,89
第四次排序:36和61比较,36小于61,不交换位置 1,10,35,36,55,61,89
第三趟总共进行了4次比较,排序结果:1,10,35,36,55,61,89
到目前位置已经为有序的情形了。
C++代码实现:
#include<iostream>
using namespace std;
void print(int arr[], int n)
{
for(int j= 0; j<n; j++)
{
cout<<arr[j] <<" ";
}
cout<<endl;
}
void BubbleSort(int arr[], int n)
{
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
int main()
{
int s[7] = {10,1,35,61,89,36,55};
cout<<"初始序列:";
print(s,7);
BubbleSort(s,7);
cout<<"排序结果:";
print(s,7);
system("pause");
}
例2:
排序数组:[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48]
由于第一个例子已经讲解过过程,第二个例子的排序就如下动态图所示:
4.算法分析:
(1)由此可见:N个数字要排序完成,总共进行N-1趟排序,每i趟的排序次数为(N-i)次,所以可以用双重循环语句,外层控制循环多少趟,内层控制每一趟的循环次数
(2)冒泡排序的优点:每进行一趟排序,就会少比较一次,因为每进行一趟排序都会找出一个较大值。如上例:第一趟比较之后,排在最后的一个数一定是最大的一个数,第二趟排序的时候,只需要比较除了最后一个数以外的其他的数,同样也能找出一个最大的数排在参与第二趟比较的数后面,第三趟比较的时候,只需要比较除了最后两个数以外的其他的数,以此类推……也就是说,没进行一趟比较,每一趟少比较一次,一定程度上减少了算法的量。
(3)时间复杂度
1.如果我们的数据正序,只需要走一趟即可完成排序。所需的比较次数C和记录移动次数M均达到最小值,即:Cmin=n-1;Mmin=0;所以,冒泡排序最好的时间复杂度为O(n)。
2.如果很不幸我们的数据是反序的,则需要进行n-1趟排序。每趟排序要进行n-i次比较(1≤i≤n-1),且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较和移动次数均达到最大值:
综 上 所 述 : 冒 泡 排 序 总 的 平 均 时 间 复 杂 度 为 : O ( n 2 ) , 时 间 复 杂 度 和 数 据 状 况 无 关 。 综上所述:冒泡排序总的平均时间复杂度为:O(n^2) ,时间复杂度和数据状况无关。 综上所述:冒泡排序总的平均时间复杂度为:O(n2),时间复杂度和数据状况无关。
5.总结:
-
最坏情况:冒泡排序要进行n-1轮排序循环,每轮排序循环中序列都是非正序的,则每轮排序循环中要进行n-i次比较(1<=i<=n-1),即其外循环执行n-1次,内循环最多执行n次,最少执行1次,由于内循环执行次数是线性的,故内循环平均执行(n+1)/2次,时间复杂度计算为((n-1)(n+1))/2=(-1)/2 ,时间复杂度为O(n2)
-
最好情况:待排序数组本身就是正序的,一轮扫描即可完成排序,此时时间复杂度仅为比较时的时间复杂度,为O(n)
-
时 间 复 杂 度 平 均 情 况 : O ( n 2 ) 时间复杂度平均情况:O(n^2) 时间复杂度平均情况:O(n2)
-
空间复杂度就是在交换元素时那个临时变量所占的内存空间,最优的空间复杂度就是开始元素顺序已经排好了,则空间复杂度为0,最差的空间复杂度就是开始元素逆序排序了,则空间复杂度为O(n),平均的空间复杂度为O(1)