简单冒泡排序的时间复杂度及其两种优化

本文详细介绍了冒泡排序的原理和最坏情况下的时间复杂度,即比较次数为n(n-1)/2,并指出冒泡排序的时间复杂度可以用O(N^2)表示。同时,提出了两种优化策略,一种是提前结束排序,另一种是减少不必要的交换操作,以提高排序效率。文章以实例解析了优化方法,并强调选择适合具体情况的排序算法的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


在我们写一些简单的程序中,对一组数据进行简单的有序的排列是经常会遇到的,所以我们必须熟悉几种基本的算法。

而冒泡排序就是我们学习排序的基础


冒泡排序:

形象的可以理解为:水中上升的气泡,在上升的过程中,气泡越来越小,不断比较相邻的元素,将小的往后调


我们来解决这样一个问题:

设有一数组,其大小为6个元素(int array[6]),数组内的数据是(4,2,5,3,2,6),此刻数据是无序的,现要求我们编程将其变成一个有序的从大到小的数组,从下标0开始。


思考:按照题目要求,毫无疑问,最终的有序数组应该是这样(6,5,4,3,2,2),要做到这样,最简单的办法就是进行比较交换


1:我们从数组的第一个元素array[0]向后走,如果比相邻的小,那么交换,如此进行下去,可以发现,我们找到了所

      有元素中最小的并且已经将它放在了最后一个位置array[5]

2:然后,我们重新从第一个元素向后走,还是相邻的比较,并且交换,但是我们只需要比较到4,放在array[4]

3:重复第二步,直到比较到1


代码:

#include <stdio.h>
#include <iostream>
using namespace std;

void Bubble_sort(int *array, int length)
{
        //变量i,j用于循环,变量t用于交换中间值
        int i, j, t;
        for(i = 1; i < length; i++)
        {       
                //比较的次数越来越少,但是每一个都能在相应的范围内确定一个最小值并放在合理的位置
                for(j = 0; j < length - i ; j++)
                {
                        //在满足条件的情况下,交换两个数
                        if(array[j] < array[j + 1])
                        {
                                t = array[j];
                                array[j] = array[j + 1];
                                array[j + 1] = t;
                        }
                }
        }
        //将6个数输出
        for(i = 0; i< length; i++)
                cout<<array[i]<<endl;
}

int main()
{
        int array[] = {4,2,5,3,2,6};        //定义一个数组并简单的初始化
        int length = sizeof(array)/sizeof(int);//求定义数组的具体长度
        Bubble_sort(array, length);     //调用相应的排序函数
        
        return 0;       
}

关于优化:我们必须从时间复杂度和空间复杂度上面来看

好多人一直都在纠结冒泡排序的时间复杂度

在最坏的情况下是:O(N)

还是在最坏的情况下是比较比较次数是:n(n - 1)/ 2

他们两到底是什么关系???


其实:总而言之,冒泡排序是一种用时间在换空间的排序。

最坏的情况当然是:每一次的比较都会进行交换,也就是说要把逆序的数列变成顺序或者要把顺序变成逆序

5,4,3,2,1以冒泡升序排列

1,从第一个数5开始和后面的数进行比较比较到倒数第二个数2为止,过程为:5跟4比较,5比4大,两者交换,然后

      跟3比较,5比3大,继续进行交换,依次进行比较,比较完成为:4,3,2,1,5

2,从第一个数4开始和后面的数进行比较,过程为:4跟3比较,4比3大,两者进行交换,然后跟2进行比较,4比2大

      ,继续交换,依次比较,比较完成为:3,2,1,4,5

3,同理


所以总的比较次数就是:4 + 3 + 2 + 1

所以,对于n位数的比较次数就是:n + (n - 1)+(n -2)+...+1 = n(n - 1)/ 2


而O(N^2)表示的是复杂度的数量级,举个例子来说,如果n = 10000,那么n(n -1 )/2 = (n^2 - n)/ 2

= (100000000 - 10000)/2,相对于10^8来说,10000可以忽略不计,所以总计算次数约为0.5 * N^2.

所以,就用O(N^2)表示了数量级(忽略了前面的系数0.5)



所以,我们可以从趟数上面处理,因为有可能我们比较一定的倘数之后就已经变成了有序的了,没有必要再去做一些无用的比较了

如:5,1,2,3,4

冒泡一次之后就变成了:1,2,3,4,5已经有序了,我们没有必要再去比较了


程序:

#include <stdio.h>
#include <iostream>
using namespace std;

void Bubble_sort(int *array, int length)
{
        int i, j, t;
        int flag;                    //标志量,用于指示,数列已然是有序的
        for(i = 1; i < length; i++)
        {       
                flag = 1;
                for(j = 0; j < length - i ; j++)
                {
                        if(array[j] < array[j + 1])   //合理的交换相邻的两个数
                        {
                                flag = 0;
                                t = array[j];
                                array[j] = array[j + 1];
                                array[j + 1] = t;
                        }
                }
                if(flag == 1)         //标志位
                        break;
        }
        
        for(i = 0; i< length; i++)//输出排序后的数列
                cout<<array[i]<<endl;
}

int main()
{
        int array[] = {4,2,5,3,2,6};
        int length = sizeof(array)/sizeof(int);
        Bubble_sort(array, length);
        
        return 0;       
}

这里我们加入了标志,flag,如果有一趟排序中没有产生交换的话,那么说明此刻数列以及变成了有序的数列



从上面时间复杂度看,时间主要花费在交换上面了,如果转汇编的话,比较可能只需要一条指令,而交换可能就需要很多指令,所以我们的目的就是减少某一倘的交换次数即可

如下:为了便于讲解,我们将上面用于排序的那些数列简单的改改

4,2,3,2,6,7,8

主要的就是:4,3,2,2(前面的排列),后面就是比较就是:

array[3]跟array[4]比较,2小于6,那么记录下来,继续比较array[3]和array[5],2小于7,继续比较array[3]和array[6],

2小于8,但是由于8是数列的最后一个所以我们直接交换:

所以,第一次排序的结果就是:4,3,2,8,6,7,2

可以简单的理解:

就变成这样了,,,,(理解如上)


#include <stdio.h>                                                                                                                    
#include <iostream>
using namespace std;

void Bubble_sort(int *array, int length)
{
        int i, j, t, k;
        int flag;       //flag表示减少的倘数
        for(i = 1; i < length; i++)
        {
                flag = 1;
                for(j = 0; j < length - i ; j++)
                {
                        if(array[j] < array[j + 1])   
                        {
                                flag = 0;
                                k = j+ 1;
                                while(k < length - i + 1)//确定其有效性
                                {
                                        if(array[j] >= array[k]) //这里添加等号,是为了不影响程序的稳定性
                                        {
                                                //交换array[j]与array[k - 1]
                                                t = array[j];
                                                array[j] = array[k - 1];
                                                array[k - 1] = t;
                                                break;
                                        }
                                        if(k == length - i)  //如果走到最后了,那么直接进行交换
                                        {
                                                t = array[j];
                                                array[j] = array[k];
                                                array[k] = t;
                                                break;
                                        }
                                        k++;
                                }
                                if(k == length - i)        //已经到了末尾了,可以直接退出本次的循环了
                                        break;
                                k = k - 2;
                                j = k;
                        }
                } 
                if(flag == 1)
                        break;
        }
        //输出我们排       
        for(i = 0; i< length; i++)
                cout<<array[i]<<endl;
}   

int main()
{
        //定义一个数组,并给其一个简单的初始化
        int array[] = {4,2,3,2,6,7,8};
        //求出数组的大小
        int length = sizeof(array)/sizeof(int);
        //调用排序函数
        Bubble_sort(array, length);
        
        return 0;       
}






如上程序:上面的k值就是类似与一个简单的标志



关于第三步的优化方式,可能一部分人不太认同,因为对于冒泡而言,必须是跟相邻的进行比较,然后进行交换,而我上面这个不完全是这样的,但是,我还是认为,对于程序,重要的是:

时间复杂度,空间复杂度,如果我们能针对当前的数列选择一个合理的排序方式,那就是极好的!!!

因为,不同的排序,块排,插入,基数,堆排都有自己最适合的情况,我们不能要求某一个排序必须用某一个排序,是吧,,,,

鄙人的一点简单看法,,谢谢大家指点,,,小子谢谢啦!!!






评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值