数据结构:常见的排序算法(一):冒泡排序(C++实现)

常见排序之冒泡排序

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]

img

(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]

由于第一个例子已经讲解过过程,第二个例子的排序就如下动态图所示:

img

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),且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较和移动次数均达到最大值:

img

综 上 所 述 : 冒 泡 排 序 总 的 平 均 时 间 复 杂 度 为 : 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)

猜你喜欢

转载自blog.csdn.net/qq_43801020/article/details/107937787