排序算法——1冒泡排序算法

一、冒泡排序常规算法:

冒泡排序原理:比较相邻两元素,将值大的交换到右边(从小到大排序,也可从大到小排序);

步骤:

(1)第一趟第一次比较:首先比较第一和第二个数,将小数放在前面,将大数放在后面。

(2)比较第2和第3个数,将小数放在前面,大数放在后面。

(3)重复步骤(2),直到比较到最后的两个数,将小数放在前面,大数放在后面,第一趟排序完成

(4)在第一趟比较完成后,最后一个元素一定是数组中最大的一个数,所以在比较第二趟的时候,最后一个数是不参加比较的。

(5)在第二趟比较完成后,倒数第二个数也一定是数组中倒数第二大数,所以在第三趟的比较中,最后两个数是不参与比较的。依次类推。

算法分析:

(1)N个元素排序,总共进行N-1趟排序,第 i 趟的比较次数为(N-i)次,双层循环语句,外层控制循环多少趟 for(int i=0; i<N-1; i++),内层控制每一趟的比较次数for(int j=0; j<N-i-1; j++);每次比较时当前元素比后一个元素大,就交换位置,否则比较下一次。

(2)冒泡排序的优点:每进行一趟排序,就会少比较一次,因为每进行一趟排序都会找出一个较大值。如上例:第一趟比较之后,排在最后的一个数一定是最大的一个数,第二趟排序的时候,只需要比较除了最后一个数以外的其他的数,同样也能找出一个最大的数排在参与第二趟比较的数后面,第三趟比较的时候,只需要比较除了最后两个数以外的其他的数,以此类推……每进行一趟比较,每一趟就少比较一次。

(3)时间复杂度

1.如果我们的数据是正序的,只需要走一趟即可完成排序。所需的比较次数C和记录移动次数M均达到最小值,即:Cmin=n-1;Mmin=0;冒泡排序最好的时间复杂度为O(n)。

2.如果我们的数据是反序的,则需要进行n-1趟排序。每趟排序要进行n-i次比较(1≤i≤n-1),且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较和移动次数均达到最大值:冒泡排序总的平均时间复杂度为:O(n^2)。

a[10]={89,45,76,90,31,19,24,20,54,66}

#include <stdio.h>

void maopao_sort(int *arr, int len)
{
    /*数组为空或者数组只有一个元素时,直接返回*/
    if(arr == NULL || len < 2)
        return;

    int temp;
    for(int i=0; i<len -1; i++)
    {
        for(int j=0; j<len-i-1; j++)
        {
            if(arr[j] > arr[j+1])
            {
                temp = arr[j+1];
                arr[j+1] = arr[j];
                arr[j] = temp;
            }
        }
    }
}

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

int main()
{
    int arr[] = {10,1,35,61,89,36,55};
    int len = sizeof(arr)/sizeof(int);    //计算数组长度
    printf_arr(arr, len);    //打印排序前数组
    maopao_sort(arr, len);
    printf_arr(arr, len);    //打印排序后数组

    return 0;
}

运行结果:

 

二、冒泡排序算法的优化:

在上述算法中,需要逐趟逐次的比较相邻元素的大小,如果待排序的数组中的元素大部分已经是有序的,仍然逐次比较就会比较浪费时间了,所以需要在判断当在某次比较中,各元素的位置没有发生交换时,就说明当前数组元素次序已经是有序的,不用再比较,可以结束冒泡排序。

实例:a[N]={2,1,3,4,5,6}            数组a只有前两个元素需要交换位置,在进行第一趟比较后就已经是有序的了,如果用上述算法,则仍然要继续比较下去。

初始 2 1 3 4 5 6
第一趟 1 2 3 4 5 6
第二趟 1 2 3 4 5 6

冒泡算法的改进:

可以看到,在进行第一趟排序后,数组元素已经有序排列了,再往后进行第二、三趟排序,元素位置不会有任何变化,所以关键就是要判断,元素的位置是否有变化,如果有则继续进行下一趟比较,如果没有则已经排序好,退出排序程序。

改进方法:只需在上述算法中加入一个标志量,判断是否有交换元素的情况发生

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void maopao_sort(int *arr, int len)
{
    /*数组为空或者数组只有一个元素时,直接返回*/
    if(arr == NULL || len < 2)
        return;
    int flag=1;  //是否发生元素交换的标志量
    int temp;
    int i=0;
    for(i=0; i<len-1 && flag; i++){
        flag = 0;
        for(int j=0; j<len-i-1; j++){
            if(arr[j] > arr[j+1]){
                temp = arr[j+1];
                arr[j+1] = arr[j];
                arr[j] = temp;
                flag = 1;
            }
        }
    }
    printf("%d\n", i);      //打印比较的趟数
}

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

int main()
{
    int arr[] = {2, 1, 3, 4, 5, 6};
    int len = sizeof(arr)/sizeof(int);
    printf_arr(arr, len);
    maopao_sort(arr, len);
    printf_arr(arr, len);

    return 0;
}

运行结果:

 可以看到只进行了两趟比较。

ps:此优化有点鸡肋。。。

猜你喜欢

转载自blog.csdn.net/Healer19/article/details/117429006
今日推荐