冒泡排序原理及两种代码实现(c/c++)

本文深入解析冒泡排序算法,介绍其基本原理与两种实现方式,包括传统比较交换法及优化后的有序标志法,帮助读者理解并掌握冒泡排序的具体操作流程。

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

有序序列中,任意一对相邻元素都是顺序排列。

无序序列中,至少有一对相邻元素为逆序排列。

冒泡法是一种经典且稳定的排序方法。它采取相邻元素之间进行比较的策略,若顺序相反则交换元素位置,逐渐将大数沉底,小数上浮(或相反)。在程序上有两种实现方式:

第一种方式

假设数组中有 n 个元素,从第一个元素开始依次与相邻元素做比较,若顺序相反则交换位置。直到最后一个元素参与比较,将会发生 n-1 次元素比较,此刻最大元素必将落位最右端,这个过程我们称为第一轮交换。接着我们重新从第一个元素开始依次与相邻元素做比较,若顺序相反则交换位置,直到倒数第二个元素参与比较(经过第一轮交换最后一个元素必定是最大元素,故无需再参与比较),将会发生 n-2 次比较,此时次大元素必将落位数组的倒数第二个位置……以此类推,每轮比较过后将会减少一个无序元素,第 i 轮参与比较的无序元素个数为 n-i+1,比较次数为 n-i 。容易得知,当我们进行 n-1 轮元素比较之后,将会有 n-1 个元素落位,还剩下 1 个元素必定为最小元素,即所有元素完成排序。

综上所述,完成 n 个元素数组的排序共需要进行 n-1 轮扫描比较,第 i 轮需要进行 n-i 次元素比较。代码如下:

//考虑到数组元素下标从 0 开始,将轮次和比较次数都统一为从 0 开始
void bubblesort(int A[],int n) //或者void bubblesort(int *a,int n),其中n表示数组元素个数。因为数组名本质上也是指针,所以传入数组名可以成功完成元素交换;如果是交换两个变量的值则不可以传入变量名必须传入变量指针
{
    for (int i = 0; i < n - 1; i++)  // i的取值范围为[0,n-2],共n-1轮
    {
        for (int j = 0; j < n - 1 - i; j++)  // j的取值范围为[0,n-2-i],共n-1-i次。前面我们分析时说过,第i轮,需做n-i次比较,为什么这里又变成了n-1-i次呢?这是因为我们分析时考虑的是轮次i从1开始计算,第1轮无序元素为n个,因此要比较n-1次。而这里我们设定轮次i从0开始计算,即i=0时其实是第1轮,i=1时其实是第2轮……因此我们计算比较次数时将轮次计算为i+1,即第i轮需要比较n-(i+1)=n-1-i次,0 ~ n-1-(i+1)为n-1-i次
        {
            if (A[j]>A[j + 1])
            {
                A[j] = A[j] + A[j + 1];  
                A[j + 1] = A[j] - A[j + 1];
                A[j] = A[j] - A[j + 1];
            }
        }
    }
}


//或者更直观些:令轮次从 1 开始,比较次数从 1 开始

void bubblesort(int A[],int n) 
{
    for (int i = 1; i < n; i++)  //i的取值范围为[1,n-1],共n-1轮
    {
        for (int j = 1; j <= n - i; j++)  //第i轮,需做n-i次比较,取值范围为[1,n-i]
        {
            if (A[j-1]>A[j])
            {
                A[j-1] = A[j-1] + A[j]; //注意j从1开始取值,而数组元素下标从0开始,因此操作数组元素时应从j-1开始
                A[j] = A[j-1] - A[j];
                A[j-1] = A[j-1] - A[j];
            }
        }
    }
}

第二种方式

第二种实现方式是第一种实现方式的改进版。算法思想仍然是从数组头部开始逐轮扫描数组元素,依次比较每一对相邻元素,逆序则进行交换。区别是,这次我们设置一个有序标志,标识数组是否完成排序。在一轮扫描开始前,将有序标志初始化为true,然后进行该轮次扫描。若扫描过程中发现了逆序元素,则交换逆序元素并将有序标志更改为false,否则不做任何操作。扫描过程结束后判断有序标志是否为真,为真直接跳出循环,为假则继续新一轮的扫描。代码如下:

void bubblesort(int A[],int n)
{
    for(bool sorted=false;sorted=!sorted/*每一轮扫描前将有序标志设置为true*/;n--)
        for(int i=1;i<n;i++)
            if (A[j-1]>A[j])
            {
                A[j-1] = A[j-1] + A[j]; 
                A[j] = A[j-1] - A[j];
                A[j-1] = A[j-1] - A[j];
                sorted=false;
            }
}



//或者写的更直观一些,很容易看出是第一种实现方式的改进版,若原始序列的已排序程度较高可显著减少比较次数和轮次,交换次数不变

void bubblesort(int A[],int n)
{
    for(int i = 1; i < n; i++)
    {
        bool sorted=true;
        for(int j = 1; j <= n - i; j++)
            if (A[j-1]>A[j])
            {
                A[j-1] = A[j-1] + A[j]; 
                A[j] = A[j-1] - A[j];
                A[j-1] = A[j-1] - A[j];
                sorted=false;
            }
        if(sorted==true)
            break;
    }
}

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值