首页 > 编程笔记 > C语言笔记 阅读:12

C语言数组排序的5种方法(附带实例)

C语言中的数组是一组有序数据的集合。这里,“有序”指的是数组元素在内存中的存放方式是有序的,其引用方式也有规律可循,而不是说数组元素在数组中是按照数值大小有序排列的。

那么,有没有可能让数组元素按照数值大小有序排列呢?当然可以,下面就一起来学习下数组的各种常用排序算法。

1、C语言选择法排序数组

选择法排序的原理如下:每次在待排序数组中查找最大或最小的数组元素,将其值与最前面没有进行过排序的数组元素的值互换。这里,由大到小排序应查找最大值,由小到大排序则应查找最小值。

下面以数字 9、6、15、4、2 为例,利用选择法使其从小到大排序,每次交换后的数字顺序如下表所示。

表:选择法排序(从小到大)
排序过程 元素【0】 元素【1】 元素【2】 元素【3】 元素【4】
起始值 9 6 15 4 2
第1次 2 6 15 4 9
第2次 2 4 15 6 9
第3次 2 4 6 15 9
第4次 2 4 6 9 15
排序结果 2 4 6 9 15


依此类推,每次都将下一个数字和剩余数字中最小的数字进行位置互换,直到将一组数字按从小到大排序。

【实例】声明了一个整型数组和两个整型变量。其中,整型数组用于存储用户输入的 10 个数值,而整型变量用于存储数值最小的数组元素和该元素的位置。通过双层循环进行选择法排序,最后将排好序的数组元素输出。
#include<stdio.h>
int main()
{
    int i,j;
    int a[10]={65,45,32,13,67,98,75,42,18,23};  /*定义数组,存储用户输入的10个数*/
    int iTemp;  /*定义变量,表示最小的数组元素*/
    int iPos;  /*定义变量,表示元素位置*/
    /*使用选择法对数组元素从小到大排序*/
    for(i=0;i<9;i++)  /*设置外层循环下标为0~8,表示前9个数组元素*/
    {
        iTemp = a[i];  /*假设当前元素为最小值*/
        iPos = i;  /*记录最小元素位置*/
        for(j=i+1;j<10;j++)  /*设置内层循环下标为i+1~9,表示剩下的未排序数组元素部分*/
        {
            if(a[j]<iTemp)  /*如果后续的元素中有数比前面设定的最小值还小*/
            {
                iTemp = a[j];  /*重新设定最小值*/
                iPos = j;  /*修正最小元素位置*/
            }
        }
        a[iPos] = a[i];  /*此两行代码用于将最小的数组元素和当前排序次数对应的数组元素互换*/
        a[i] = iTemp;
    }
    printf("排序结果如下:\n");  /*输出数组*/
    for(i=0;i<10;i++)  /*输出数组*/
    {
        printf("%d\t",a[i]);  /*用制表位分隔数据*/
        if(i == 4)  /*如果是第5个元素*/
            printf("\n");  /*输出换行*/
    }
    printf("\n");  /*程序结束*/
    return 0;
}
1) 声明一个整型数组,并通过键盘输入为数组元素赋值。

2) 设置一个嵌套循环:
当所有循环都完成以后,就将数组元素按照从小到大的顺序重新排列了。

3) 循环输出数组中的元素,并在输出 5 个元素以后换行,在下一行输出后面的 5 个元素。

运行程序,结果为:
排序结果如下:
13      18      23      32      42
45      65      67      75      98

2、C语言冒泡法排序数组

冒泡法排序的原理如下:每次比较数组中相邻的两个数组元素的值,将较小的数排在较大的数前面,可实现数组元素从小到大排序;每次将较大的数排在较小的数前面,可实现数组元素从大到小排序。

仍以数字 9、6、15、4、2 为例,对这几个数字进行冒泡法排序,使其从小到大排列。每次排序后的顺序如下表所示。

表:冒泡法排序(从小到大)
排序过程 元素【0】 元素【1】 元素【2】 元素【3】 元素【4】
起始值 9 6 15 4 2
第1次 2 9 6 15 4
第2次 2 4 9 6 15
第3次 2 4 6 9 15
第4次 2 4 6 9 15
排序结果 2 4 6 9 15


依此类推,每次都将剩余数字中最小的数字移动到当前剩余数字的最前方,直到将一组数字按从小到大排序为止。

【实例】冒泡法从小到大排序。声明一个整型数组和一个整型变量,整型数组用于存储用户输入的数字,整型变量作为两个元素交换时的中间变量,通过双层循环进行冒泡法排序,最后将排好序的数组输出。
#include<stdio.h>
int main()
{
    int i,j;
    int a[10]={65,45,32,13,67,98,75,42,18,23};
    int iTemp;
    /*采用冒泡法使数组元素从小到大排序*/
    for(i=1;i<10;i++) /*外层循环元素的下标为 1~9,表示后9个数组元素*/
    {
        for(j=9;j>=i;j--) /*内层循环元素的下标为 9~i,表示从最后一个元素开始向前循环*/
        {
            if(a[j]<a[j-1]) /*如果前一个数比后一个数大*/
            {
                /*交换两个数组元素的值,使小数前移,如同冒泡*/
                iTemp = a[j-1];
                a[j-1] = a[j];
                a[j] = iTemp;
            }
        }
    }
    printf("排序结果如下:\n"); /*输出数组*/
    for(i=0;i<10;i++)
    {
        printf("%d\t",a[i]); /*用制表位分隔数据*/
        if(i == 4) /*如果是第5个元素*/
            printf("\n"); /*输出换行*/
    }
    printf("\n");
    return 0; /*程序结束*/
}
1) 声明一个整型数组,并通过键盘输入为数组元素赋值。

2) 设置一个嵌套循环,第一层循环为后 9 个数组元素。在第二层循环中,从最后一个数组元素开始向前循环,直到前面第一个没有进行排序的数组元素。循环比较这些数组元素,如果在比较中后一个数组元素的值小于前一个数组元素的值,则将两个数组元素的值进行互换。当所有循环都完成以后,就将数组元素按照从小到大的顺序重新排列了。

3) 循环输出数组中的元素,并在输出5个元素以后进行换行,在下一行输出后面的 5 个元素。

运行程序,结果为:
排序结果如下:
13      18      23      32      42
45      65      67      75      98

3、C语言交换法排序数组

交换法排序是将每一位数与其后的所有数一一比较,如果发现符合条件的数据,则交换数据。

首先,用第一个数依次与其后的所有数进行比较,如果存在比其值大(小)的数,则交换这两个数,继续向后比较其他数直至最后一个数。然后再使用第二个数与其后面的数进行比较,如果存在比其值大(小)的数,则交换这两个数。继续向后比较其他数,直至最后一个数比较完成。

下面以数字 9、6、15、4、2 为例,进行交换法排序。每次排序后的顺序如下表所示。

表:交换法排序(从小到大)
排序过程 元素【0】 元素【1】 元素【2】 元素【3】 元素【4】
起始值 9 6 15 4 2
第1次 2 9 15 6 4
第2次 2 4 15 9 6
第3次 2 4 6 15 9
第4次 2 4 6 9 15
排序结果 2 4 6 9 15

可以发现,在第一次排序过程中将第一个数与后边的数依次进行比较:
【实例】交换法从小到大排序。声明一个整型数组和一个整型变量,其中整型数组用于存储用户输入的数字,整型变量则作为两个元素交换时的中间变量,然后通过双层循环进行交换法排序,最后将排好序的数组输出。
#include<stdio.h>
int main()
{
    int i,j;
    int a[10]={65,45,32,13,67,98,75,42,18,23};
    int iTemp;
    /*采用交换法使数组元素从小到大排序*/
    for(i=0;i<9;i++) /*外层循环元素下标为 0~8,表示前9个数组元素*/
    {
        for(j=i+1;j<10;j++) /*内层循环元素下标为 i+1~9,表示后面的待比较数组元素*/
        {
            if(a[j] < a[i]) /*如果后一个数比前一个数小*/
            {
                iTemp = a[i]; /*交换两个数组元素的值,使小数前移*/
                a[i] = a[j];
                a[j] = iTemp;
            }
        }
    }
    printf("排序结果如下:\n"); /*输出数组*/
    for(i=0;i<10;i++)
    {
        printf("%d\t",a[i]); /*用制表位分隔数据*/
        if(i == 4) /*如果是第5个元素*/
            printf("\n"); /*输出换行*/
    }
    printf("\n");
    return 0; /*程序结束*/
}
1) 声明一个整型数组,并通过键盘输入为数组元素赋值。

2) 设置一个嵌套循环,第一层循环为前 9 个数组元素,然后在第二层循环中,将第一个数组元素与后面的数组元素依次进行比较,如果后面的数组元素值小于当前数组元素值,则交换两个元素值,然后使用交换后的第一个数组元素继续与后面的数组元素进行比较,直到本次循环结束。将最小的数组元素值交换到第一个数组元素的位置,然后从第二个数组元素开始,继续与后面的数组元素进行比较。依此类推,直到循环结束,就将数组元素按照从小到大的顺序重新排列了。

3) 循环输出数组中的元素,并在输出 5 个元素以后进行换行,在下一行输出后面的 5 个元素。

运行程序,结果为:
排序结果如下:
13      18      23      32      42
45      65      67      75      98

4、C语言插入法排序数组

插入法排序较为复杂,其基本原理是:抽出一个数据,在前面的数据中寻找相应的位置插入,然后继续下一个数据,直到完成排序。

下面以数字 9、6、15、4、2 为例,使用插入法使其从小到大排序。每次排序后的顺序如下表所示。

表:插入法排序(从小到大)
排序过程 元素【0】 元素【1】 元素【2】 元素【3】 元素【4】
起始值 9 6 15 4 2
第1次 9        
第2次 6 9      
第3次 6 9 15    
第4次 4 6 9 15  
排序结果 2 4 6 9 15

在第一次排序过程中将第一个数取出来,并放置在第一个位置;
【实例】声明一个整型数组和两个整型变量,其中整型数组用于存储用户输入的数字,一个整型变量作为两个元素交换时的中间变量,一个用于记录数组元素的位置,然后通过双层循环进行交换法排序,最后将排好序的数组输出。
#include<stdio.h>
int main()
{
    int i;
    int a[10]={65,45,32,13,67,98,75,42,18,23};
    int iTemp;
    int iPos;
    /*采用插入法使数组元素从小到大排序*/
    for(i=1;i<10;i++) /*外层循环元素下标为 1~9,表示后9个数组元素*/
    {
        iTemp = a[i]; /*设置插入值*/
        iPos = i-1;
        while((iPos>=0) && (iTemp<a[iPos])) /*内层循环,寻找插入值的位置*/
        {
            a[iPos+1] = a[iPos]; /*插入数值*/
            iPos--;
        }
        a[iPos+1] = iTemp;
    }
    printf("排序结果如下:\n"); /*输出数组*/
    for(i=0;i<10;i++)
    {
        printf("%d\t",a[i]); /*用制表位分隔数据*/
        if(i == 4) /*如果是第5个元素*/
            printf("\n"); /*输出换行*/
    }
    printf("\n");
    return 0; /*程序结束*/
}
1) 声明一个整型数组,并通过键盘输入为数组元素赋值。

2) 设置一个嵌套循环,第一层循环为后 9 个数组元素,将第二个元素赋值给中间变量,并记录前一个数组元素的下标位置。

在第二层循环中,首先要判断是否符合循环的条件,允许循环的条件是记录的下标位置必须大于等于第一个数组元素的下标位置,并且中间变量的值小于之前设置下标位置的数组元素,如果满足循环条件,则将设置下标位置的数组元素赋值给当前的数组元素,然后将记录的数组元素下标位置向前移动一位,继续进行循环判断。

内层循环结束以后,将中间变量中保存的数值赋值给当前记录的下标位置之后的数组元素,继续进行外层循环,将数组中下一个数组元素赋值给中间变量,再通过内层循环进行排序,依此类推,直到循环结束,就将数组元素按照从小到大的顺序重新排列了。

3) 循环输出数组中的元素,并在输出 5 个元素以后进行换行,在下一行输出后面的 5 个元素。

运行程序,结果为:
排序结果如下:
13      18      23      32      42
45      65      67      75      98

5、C语言折半法排序数组

折半法排序又称为快速排序,其基本原理为:选择一个中间值(在程序中使用数组中间元素的值),然后把比中间值小的元素放在左边,比中间值大的元素放在右边(具体的实现是从两边查找,找到一对后进行交换),然后再对左右两边分别递归使用折半法排序过程。

下面以数字 9、6、15、4、2 为例,对这几个数字使用折半法从小到大排序。每次排序后的顺序如下表所示。

表:折半法排序(从小到大)
排序过程 元素【0】 元素【1】 元素【2】 元素【3】 元素【4】
起始值 9 6 15 4 2
第1次 9 6 2 4 15
第2次 4 6 2 9 15
第3次 4 2 6 9 15
第4次 2 4 6 9 15
排序结果 2 4 6 9 15

可以发现,在第一次排序过程中,首先获取数组中间元素的值 15,从左右两侧分别取出数组元素与中间值进行比较:
右侧的比较正好与左侧相反:
当中间值两侧的数据都比较一遍以后,左侧以第一个元素为起点,以中间值的元素为终点,用上面的方法继续进行比较;右侧则以中间值的元素为起点,以数组最后一个元素为终点,用上述的方法继续进行比较。

当比较完成以后,继续以折半的方式进行比较,直到将一组数字全部按从小到大的顺序排序为止。

【实例】声明了一个整型数组,用于存储用户输入的数字,再定义一个函数,用于对数组元素进行排序,最后将排序好的数组输出。
#include<stdio.h>
void CelerityRun(int left, int right, int array[]) /*声明函数*/
{
    int i,j;
    int middle,iTemp;
    i = left;
    j = right;
    middle = array[(left+right)/2]; /*求中间值*/
    do
    {
        while((array[j]<middle) && (i<right)) /*从左查找小于中间值的数*/
            i++;
        while((array[i]>middle) && (j>left)) /*从右查找大于中间值的数*/
            j--;
        if(i<=j) /*如果找到一对值*/
        {
            iTemp = array[i];
            array[i] = array[j];
            array[j] = iTemp;
            i++;
            j--;
        }
    }while(i<=j); /*如果两边的下标交错,就停止(完成一次)*/
    if(left<j) /*递归左半边*/
        CelerityRun(left,j,array);
    if(i<right) /*递归右半边*/
        CelerityRun(i,right,array);
}

int main()
{
    int i;
    int a[10]={1,2,3,4,5,6,7,8,9,10};

    CelerityRun(0,9,a); /*调用折半排序函数*/
    printf("排序结果如下:\n"); /*输出数组*/
    for(i=0;i<10;i++)
    {
        printf("%d\t",a[i]); /*用制表位分隔数据*/
        if(i == 4) /*如果是第5个元素*/
            printf("\n"); /*输出换行*/
    }
    printf("\n");
    return 0; /*程序结束*/
}
1) 声明一个整型数组,并通过键盘输入为数组元素赋值。

2) 定义折半排序函数 CelerityRun(),用于对数组元素进行排序,3 个参数分别表示递归调用时数组最开始元素的下标、最后元素的下标以及要排序的数组。

声明两个整型变量,作为控制排序算法循环的条件,分别将两个参数赋值给变量 i 和 j,i 表示左侧下标,j 表示右侧下标。首先使用 do…while 语句设计外层循环,条件为 i≤j,表示如果两边的下标交错,就停止循环。

内层的两个循环分别用来比较中间值两侧的数组元素:
然后判断 i 的值是否小于等于 j,如果是,则交换以 i 和 j 为下标的两个元素值,继续进行外层循环。

当外层循环结束以后,以数组第一个元素到以 j 为下标的元素为参数递归调用该函数,同时,以 i 为下标的数组元素到数组最后一个参数也作为参数递归调用该函数。

依此类推,直到将数组元素按照从小到大的顺序重新排列为止。

3) 循环输出数组中的元素,并在输出5个元素以后进行换行,在下一行输出后面的 5 个元素。

运行程序,结果为:
排序结果如下:
10      9       8       7       6
5       4       3       2       1

排序算法的比较

前面介绍了 5 种排序算法,在具体应用时应该怎么选择呢?下面对 5 种排序算法的擅长方向进行总结。
总之,插入法、冒泡法、交换法排序的速度较慢,但当参加排序的序列局部或整体有序时,这种排序能达到较快的速度;在这种情况下,折半法排序反而会显得速度慢了。当 n 较小,对稳定性不作要求时,宜选用选择法排序;对稳定性有要求时,宜选用插入法或冒泡法排序。

相关文章