75-交换排序——冒泡排序

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35733751/article/details/81905461

1. 交换排序

  交换排序的基本思想就是:两两比较待排序记录的关键字,如果两个记录的次序相反时即进行交换,直到所有记录中没有反序(反序指的是,大的记录在前,小的记录在后)的记录为止。

这里写图片描述
图1-交换排序

  例如,在图1这个待排序列的所有记录中,如果7和2这两个记录是反序的,那么就交换两个记录的位置,直到这个序列中没有反序的记录,而这个排序的过程就是交换排序。

  典型的交换排序算法有:冒泡排序和快速排序,在这两种排序算法中,其核心思想都是通过交换两个反序的记录的位置来完成排序的,但不同的排序算法在进行交换时,采取的策略是不一样的。

2. 冒泡排序

  冒泡排序的思想:不停地比较相邻的两个记录,如果相邻的两个记录的次序是反序则交换,直到所有的记录都已经排好序了(使关键字最小的记录如气泡一般逐渐往上“漂浮”直至“水面”,所以叫冒泡排序)。


3. 冒泡排序的过程

  假设现在有这样一个待排关键字序列:{23,38,22,45,23,17,31,15,41},这个序列中有n个元素,需要进行n-1趟排序,那么从前往后依次比较相邻的两个关键字,如果是反序的就交换记录,如果不是则继续往后比较。



下面我们来看一下冒泡排序过程的动画演示:

这里写图片描述
图2-冒泡排序

  通过冒泡排序过程可知,每一趟排序完毕后,最大的数都会出现在最后,因此在下一趟比较的时候就可以跳过这个最大的数字了。比如第一趟比较完毕后,最大的数45就会出现在最后的位置,那么在下一趟排序的过程中就不用比较45了,第二趟,第三趟 ….. 以此类推


4. 冒泡排序算法

冒泡排序算法的代码实现:

void BubbleSort(RecType R[] , int n)
{
    int i;
    int j;
    RecType temp;
    //比较n-1趟
    for(i = 0; i < n-1; i++)
    {
        for(j = 0; j < n-1-i; j++)
        {
            //比较相邻的记录,如果是逆序则交换
            if(R[j+1].key < R[j].key)
            {
                temp.key = R[j+1].key;
                R[j+1].key = R[j].key;
                R[j].key = temp.key;
            }
        }
    }
}


int main(void)
{
    RecType R[MAXSIZE] = {0};
    int arr[] = {23,38,22,45,23,17,31,15,41};
    int i;
    printf("--------排序前--------\n");
    for(i = 0; i < MAXSIZE; i++)
    {
        R[i].key = arr[i];
        printf("R[%d].key = %d\n" , i , R[i].key);
    }
    //冒泡排序
    BubbleSort(R,MAXSIZE);
    printf("--------排序后--------\n");
    for(i = 0; i < MAXSIZE; i++)
    {
        printf("R[%d].key = %d\n" , i , R[i].key);
    }
    return 0;
}



测试结果:
这里写图片描述


5. 冒泡排序改进版

  其实上面这个冒泡排序算法是有缺点的,比如现在有这样一个接近已完成排序的关键字序列:{17,15,22,23,23,31,38,41,45},其实只要一趟排序,把17和15交换位置就可以完成排序。但是按照冒泡排序算法还是会进行n-1趟排序,显然,这多出来的几趟排序是有些多余的。

  通过仔细分析可以发现,整个排序的过程只需要2趟就可以完成,第一趟交换17和15关键字的位置,然后第二趟在进行比较时,如果没有交换的记录,则说明这个序列已经是有序的了,不需要再继续比较了。

  因此我们改进的地方就是,定义一个变量flag检查每一趟排序是否交换了位置, 如果没有交换,此时flag为false,说明序列已经有序了,不需要再继续循环了。

这里写图片描述
图3-冒泡排序改进版



冒泡排序改进版代码如下:

//冒泡排序改进版
void BubbleSort2(RecType R[] , int n)
{
    int i;
    int j;
    RecType temp;
    for(i = 0; i < n-1; i++)
    {   
        //定义标志,默认false
        Bool falg = FALSE;
        for(j = 0; j < n-1-i; j++)
        {
            if(R[j+1].key < R[j].key)
            {
                temp.key = R[j+1].key;
                R[j+1].key = R[j].key;
                R[j].key = temp.key;
                //更改标志
                falg = TRUE;
            }
        }
        //判断每一趟排序是否交换位置,如果没有则直接返回
        if(falg == FALSE)
        {
            return;
        }
    }
}

6. 冒泡排序的性能

  1. 对于最好的情况就是待排关键字序列本身就是有序的,如关键字序列:{15,17,22,23,23,31,38,41,45},只需进行一趟冒泡,且移动的次数为0,比较的次数为n-1,也就是说最好的情况下,时间复杂度为 O ( n )


  2. 最坏的情况就是待排关键字序列本身就是逆序的,如{45,41,38,31,23,23,22,17,15},需要比较n-1趟,且每一趟的比较的次数随着i而变化,比较次数为 n i 1 ,总的比较次数为:

i = 0 n 1 ( n i 1 ) = n ( n 1 ) 2

  同时,每次比较进行交换位置的时候,都需要三次移动,因此总的移动次数为:

i = 1 n 2 3 ( n i 1 ) = 3 n ( n 1 ) 2

  那么最坏情况下,时间复杂度为 O ( n 2 ) ,也就是说冒泡排序算法的平均时间复杂度为 O ( n 2 )



  3. 对于稳定性来说,冒泡排序算法在比较两个相同的关键字时不会交换位置,因此冒泡排序是一个稳定排序算法。

猜你喜欢

转载自blog.csdn.net/qq_35733751/article/details/81905461