排序——冒泡排序法

霸气de小男生 提交于 2019-12-01 00:01:16

一、冒泡排序法概述

    冒泡排序法的基本思想是:对待排序记录关键字从后往前(逆序)进行多遍扫描,当发现相邻两个关键字的次序与排序要求的规则不符时,就将这两个记录进行交换。这样,关键字较小的记录将逐渐从后面向前面移动,就像气泡在水中向上浮一样,所以该算法也称为气泡排序法。(提示:冒泡排序法也可使较大的记录排在前面)
    假设需要排序的记录有n个,其关键字保存在数组a中,使用冒泡排序法,需对数组a进行n-1次扫描,完成排序操作,具体过程如下:
(1)将A[n]与A[n-1]进行比较,若A[n]<A[n-1],则交换两元素的位置。
(2)修改数组下标,使需要比较的两个元素为A[n-1]和A[n-2],重复步骤1,对这两个元素进行比较。重复这个过程,直到对A[2]和A[1]进行比较完为止。完成第1遍扫描,如下图所示。

3)经过第1遍扫描后,最小的元素已经像气泡一样“浮”到最上面,即位于元素A[1]中了。接下来重复前面的步骤,进行第2遍扫描,只是扫描到A[3]与A[2]进行比较完为止(因为A[1]中已经是最小的数据,不用再进行比较)。
(4)通过n-1遍扫描,前n-1个数都已经排序完成,最后一个元素A[n]肯定就是最大的数了。至此,完成排序操作。(提示:在以上描述中,为了让读者容易理解,假设数组元素是保存在A[1]~A[n]中的,由于C语言的数组元素下标是从0开始的,因此,需要修改数组的下标)


下面以一组待排序的数据演示冒泡排序的过程,假设有6个需要排序的数据序列如下:
69,65,90,37,92,6
通过冒泡排序法对这6个数据进行排序,其排序过程如下图所示。


第1遍从下向上扫描,首先对最后两个元素A[5]和A[4]进行比较,因92>6,将6上浮到A[4],92下沉到A[5]。接着将A[4]中的6和A[3]比较,6仍然较小,继续上浮至A[3]……这样经过n-1次比较,6上浮到A[0],完成第1遍扫描。此时A[0]中保存着当前数列中的最小数。完成最小数的冒泡过程。

第2遍扫描仍然从A[5]开始,至A[1]时结束,将37上浮到A[1]。
类似的方法,在第3遍扫描时,65上浮到A[2]中,至此,所有数都已按从小到大的顺序排列,但程序还需要进行第4遍和第5遍的扫描,因为程序并不知道后面的数据是否为有序的。

二、冒泡排序法实现

(1)冒泡排序法

void BubbleSort(int a[], int n)
{
    int i, j, t;

    for (i=0; i<n; i++) {
        for (j=n-1; j>i; j--) {
            if (a[j-1] > a[j]) {
                t = a[j-1];
                a[j-1] = a[j];
                a[j] = t;
            }
        
        }
        
        printf("第%d遍:", i+1);
        for (j=0; j<n; j++)
            printf("%d ", a[j]);
        printf("\n");
    }

}

(2)数组显示

void ShowData(int arr[], int n)
{
    int i;
    for (i=0; i<n; i++)
        printf("%d ", arr[i]);
    printf("\n");

    return;
}

(3)冒泡排序法测试

#include <stdio.h>
#define ARRAYLEN 6

int main(int argc, char *argv[])
{
    int i;
    int a[ARRAYLEN] = {69, 65, 90, 37, 92, 6};

    printf("原数据:");
    ShowData(a, ARRAYLEN);

    BubbleSort(a, ARRAYLEN);
    printf("排序后:");
    ShowData(a, ARRAYLEN);

    return 0;
}

(4)运行结果

三、冒泡排序法改进

    从上面的BubbleSort函数的过程可以看出,使用冒泡排序法对n个数据进行排序,一共需要进行n-1次的比较。如果本来就是有顺序的数据,也需要进行n-1次比较。这就造成了冒泡排序法的算法虽然简单,但效率较差。
    为了提升冒泡排序法的效率,可对BubbleSort函数进行改进,当在某一遍扫描时,发现数据都已经按顺序排列了,就不再进行后面的扫描,而结束排序过程。
    如何知道数据已经按顺序排好了呢?从上图可以看出,当第3遍扫描后,数据已经按顺序排列好了,第4遍扫描时将没有数据进行交换。因此,可以设置一个标志变量flag,在每一遍扫描之前将其值设置为0,在扫描数据过程中,若有数据交换,则设置其值为1。在一遍扫描完成之后,判断flag的值,若其值为0,表示在这一遍扫描中已经没有数据进行交换,数据已经按顺序排列,就不需要再进行后续的扫描了。


编程经验:为了提高排序效率,引进了一个标志变量。即通过内存空间使用上的增多来使程序执行效率得到提升,这称为“以空间换时间”。

(1)改进冒泡排序法的实现

void BubbleSortNew(int a[], int n)
{
    int i, j, t, flag=0;

    for (i=0; i<n; i++) {
        for (j=n-1; j>i; j--) {
            if (a[j-1] > a[j]) {
                t = a[j-1];
                a[j-1] = a[j];
                a[j] = t;
                flag = 1;
            }
        
        }
        
        printf("第%d遍:", i+1);
        for (j=0; j<n; j++)
            printf("%d ", a[j]);
        printf("\n");


        if (flag == 0)
            break;
        else 
            flag = 0;
    }

}

(2)改进冒泡排序法测试

#include <stdio.h>
#define ARRAYLEN 6

int main(int argc, char *argv[])
{
    int i;
    int a[ARRAYLEN] = {69, 65, 90, 37, 92, 6};

    printf("原数据:");
    ShowData(a, ARRAYLEN);

    BubbleSortNew(a, ARRAYLEN);
    printf("排序后:");
    ShowData(a, ARRAYLEN);

    return 0;
}

(3)运行结果

可以看出来,当第3遍扫描后,数据已经按顺序排列好了,第4遍扫描时将没有数据进行交换,就不再进行后面的扫描,而结束排序过程。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!