排序算法之冒泡算法

冒泡排序算法的有两种方式,如下:

一、邻比法:

1. 依次比较相邻的两个数,将小数放在前面,大数放在后面。即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后。然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。至此第一趟结束,将最大的数放到了最后。

2. 在第二趟:仍从第一对数开始比较(因为可能由于第2个数和第3个数的交换,使得第1个数不再小于第2个数),将小数放前,大数放后,一直比较到倒数第二个数(倒数第一的位置上已经是最大的),第二趟结束,在倒数第二的位置上得到一个新的最大数(其实在整个数列中是第二大的数)。

3. 如此下去,重复以上过程,直至最终完成排序。

 

二、 逐比法:

1. 从第一个元素开始与后边所有元素两两比较,接着第二元素与后边所有元素两两比较,以此类推。即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后。然后比较第1个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。至此第一趟结束,将最小的数放到了第1位上。

2. 在第二趟:比较第2个和第3个数,将小数放前,大数放后。然后比较第2个数和第4个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。至此第二趟结束,将第二小的数放到了第2位上。

3. 如此下去,重复以上过程,直至最终完成排序。

 

冒泡算法的度量如下:

数据结构    数组
最差时间复杂度    O(n^2)
最优时间复杂度    O(n)
平均时间复杂度    O(n^2)
最差空间复杂度    总共O(n),需要辅助空间O(1)
最佳算法    No

 

上边的两种方法,也可以从后往前进行比较,所以可以演化出4种排法,可以参见下边的源码1-4。

此四种算法可以做如下改进:

在排序过程中,执行完最后的排序后,虽然数据已全部排序完备,但程序无法判断是否完成排序,为了解决这一不足,可设置一个标志位flag,将其初始值设置为非0,表示被排序的表是一个无序的表,每一次排序开始前设置flag值为0,在进行数据交换时,修改flag为非0。在新一轮排序开始时,检查此标志,若此标志为0,表示上一次没有做过交换数据,则结束排序;否则进行排序;参见下边第5个源码


1.

i∈[0,N-1)              //从前往后循环N-2遍
 j∈[0,N-1-i)           //每遍循环要处理的无序部分
 swap(j,j+1)          //从第一个元素开始相连两两比较(升序/降序),第一遍会将最大(或者最小)的元素一步一步移到最后的位置上,第二遍会将第二大(或者第二小)的元素一步一步移到倒数第二个位置上

源码:

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

void print_ary( int * ary, unsigned int len )
{
    while( len-- > 0 ) {
        printf("%d ", *ary++ );    
    }
    putchar('\n');
}

void create_rondom_number(int **parray, unsigned int number)
{
    struct timeval tpstart;
    unsigned int i =0;

    if (NULL != *parray)
    {
        return;
    }

    *parray = (int *)malloc(sizeof(unsigned int) * number);
    (void)memset(*parray, 0, sizeof(unsigned int) * number);
    
    gettimeofday(&tpstart,NULL);

    //srandom(time(NULL));
    srandom(tpstart.tv_usec);

    for (i=0; i<number; ++i)
    {
        //(*parray)[i] = random()%number; // range is [0, number-1] 
        //(*parray)[i] = random()%(b-a) + a; //range is [a, b)
        ((*parray)[i] = 1 + (int) ((double)number * rand() / (RAND_MAX + 1.0))); // [1, number]
    }
}

/*
 * i∈[0,N-1)      //从前往后循环N-2遍
 * j∈[0,N-1-i)    //每遍循环要处理的无序部分
 *  swap(j,j+1)   //从第一个元素开始相连两两比较(升序/降序),
 *                  第一遍会将最大(或者最小)的元素一步一步移到最后的位置上,
 *                  第二遍会将第二大(或者第二小)的元素一步一步移到倒数第二个位置上
 */
int bubble_sort( int * ary, int len )
{
    int i, j;
    int temp;

    for( i=0; i<len-1; ++ i ) {

        printf("\n\n");
        

        for( j=0; j<len-i-1; j++ ) {
            
            printf("a[%d] & a[%d](i=%d, j=%d) ", j, j+1, i, j);

            if( ary[j] > ary[j+1] ) {
                temp = ary[j];
                ary[j] = ary[j+1];
                ary[j+1] = temp;

                printf("swap ");
            }

            print_ary( ary, len );
        }
    }
}


int main( int argc, char ** argv )
{

    int *pary = NULL;

    if (argc !=2)
    {
        printf("\nUsage: %s Number\n", argv[0]); 
        return -1;
    }

    create_rondom_number(&pary, (unsigned int)atoi(argv[1]));    

    printf("\n\nrandom number: ");
    print_ary( pary, (unsigned int)atoi(argv[1]) );

    printf("Start sortting: \n");
    bubble_sort( pary, (unsigned int)atoi(argv[1]));

    printf("\n\nafter sorted: ");
    print_ary( pary, (unsigned int)atoi(argv[1]) );
    
    return 0;
}

运行结果:

[root@localhost sort]# ./bubble 5


random number: 5 5 3 2 5
Start sortting:


a[0] & a[1](i=0, j=0) 5 5 3 2 5
a[1] & a[2](i=0, j=1) swap 5 3 5 2 5
a[2] & a[3](i=0, j=2) swap 5 3 2 5 5
a[3] & a[4](i=0, j=3) 5 3 2 5 5


a[0] & a[1](i=1, j=0) swap 3 5 2 5 5
a[1] & a[2](i=1, j=1) swap 3 2 5 5 5
a[2] & a[3](i=1, j=2) 3 2 5 5 5


a[0] & a[1](i=2, j=0) swap 2 3 5 5 5
a[1] & a[2](i=2, j=1) 2 3 5 5 5


a[0] & a[1](i=3, j=0) 2 3 5 5 5


after sorted: 2 3 5 5 5
[root@localhost sort]#

2.

i∈[N-1,0)             //从后往前循环N-2遍
j∈[N-1,N-i-1)      //每遍循环要处理的无序部分
swap(j,j-1)          //从倒数第一个元素开始相连两两比较(升序/降序),第一遍会将最大(或者最小)的元素一步一步移到第一个位置上,第二遍会将第二大(或者第二小)的元素一步一步移到第二个位置上

源码:

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

void print_ary( int * ary, unsigned int len )
{
    while( len-- > 0 ) {
        printf("%d ", *ary++ );    
    }
    putchar('\n');
}

void create_rondom_number(int **parray, unsigned int number)
{
    struct timeval tpstart;
    unsigned int i =0;

    if (NULL != *parray)
    {
        return;
    }

    *parray = (int *)malloc(sizeof(unsigned int) * number);
    (void)memset(*parray, 0, sizeof(unsigned int) * number);
    
    gettimeofday(&tpstart,NULL);

    //srandom(time(NULL));
    srandom(tpstart.tv_usec);

    for (i=0; i<number; ++i)
    {
        //(*parray)[i] = random()%number; // range is [0, number-1] 
        //(*parray)[i] = random()%(b-a) + a; //range is [a, b)
        ((*parray)[i] = 1 + (int) ((double)number * rand() / (RAND_MAX + 1.0))); // [1, number]
    }
}

/*
 * i∈[N-1,0)            /从后往前循环N-2遍
 * j∈[N-1,N-i-1)      //每遍循环要处理的无序部分
 * swap(j,j-1)          //从倒数第一个元素开始相连两两比较(升序/降序),
 *                        第一遍会将最大(或者最小)的元素一步一步移到第一个位置上,
 *                        第二遍会将第二大(或者第二小)的元素一步一步移到第二个位置上
 */
int bubble_sort( int * ary, int len )
{
    int i, j;
    int temp;

    for( i=len-1; i>0; --i ) {

        printf("\n\n");

        for( j=len-1; j>len-i-1; --j ) {
            
            printf("a[%d] & a[%d](i=%d, j=%d) ", j, j-1, i, j);

            if( ary[j] > ary[j-1] ) {
                temp = ary[j];
                ary[j] = ary[j-1];
                ary[j-1] = temp;

                printf("swap ");
            }

            print_ary( ary, len );
        }
    }
}


int main( int argc, char ** argv )
{

    int *pary = NULL;

    if (argc !=2)
    {
        printf("\nUsage: %s Number\n", argv[0]); 
        return -1;
    }

    create_rondom_number(&pary, (unsigned int)atoi(argv[1]));    

    printf("\n\nrandom number: ");
    print_ary( pary, (unsigned int)atoi(argv[1]) );

    printf("Start sortting: \n");
    bubble_sort( pary, (unsigned int)atoi(argv[1]));

    printf("\n\nafter sorted: ");
    print_ary( pary, (unsigned int)atoi(argv[1]) );
    
    return 0;
}



运行结果:

[root@localhost sort]# ./bubble3 5   


random number: 1 1 5 5 5
Start sortting:


a[4] & a[3](i=4, j=4) 1 1 5 5 5
a[3] & a[2](i=4, j=3) 1 1 5 5 5
a[2] & a[1](i=4, j=2) swap 1 5 1 5 5
a[1] & a[0](i=4, j=1) swap 5 1 1 5 5


a[4] & a[3](i=3, j=4) 5 1 1 5 5
a[3] & a[2](i=3, j=3) swap 5 1 5 1 5
a[2] & a[1](i=3, j=2) swap 5 5 1 1 5


a[4] & a[3](i=2, j=4) swap 5 5 1 5 1
a[3] & a[2](i=2, j=3) swap 5 5 5 1 1


a[4] & a[3](i=1, j=4) 5 5 5 1 1


after sorted: 5 5 5 1 1
[root@localhost sort]#

3.

 i∈[0,N-1)                //从前往后循环N-2遍
 j∈[i+1,N)            //每遍循环要处理的无序部分
 swap(i,j)          //从第一个元素开始与后边所有元素两两比较,接着第二元素与后边所有元素两两比较,以此类推。即将最大(或者最小)的元素放到第一个位置,第二大(或第二小)的元素放到第二位置上,以此类推

源码:

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

void print_ary( int * ary, unsigned int len )
{
    while( len-- > 0 ) {
        printf("%d ", *ary++ );    
    }
    putchar('\n');
}

void create_rondom_number(int **parray, unsigned int number)
{
    struct timeval tpstart;
    unsigned int i =0;

    if (NULL != *parray)
    {
        return;
    }

    *parray = (int *)malloc(sizeof(unsigned int) * number);
    (void)memset(*parray, 0, sizeof(unsigned int) * number);
    
    gettimeofday(&tpstart,NULL);

    //srandom(time(NULL));
    srandom(tpstart.tv_usec);

    for (i=0; i<number; ++i)
    {
        //(*parray)[i] = random()%number; // range is [0, number-1] 
        //(*parray)[i] = random()%(b-a) + a; //range is [a, b)
        ((*parray)[i] = 1 + (int) ((double)number * rand() / (RAND_MAX + 1.0))); // [1, number]
    }
}
/*
* i∈[0,N-1)     //从前往后循环N-2遍
* j∈[i+1,N)     //每遍循环要处理的无序部分
* swap(i,j)     //从第一个元素开始与后边所有元素两两比较,
*                 接着第二元素与后边所有元素两两比较,以此类推。
*                 即将最大(或者最小)的元素放到第一个位置,第二大(或第二小)的元素放到第二位置上,以此类推
 */

void bubble_sort(int *a, int n)
{
    int *p1 = a;
    int *p2 = a;
    int i;
    int j;
    int tmp;

    for (i = 0; i < n-1; i++)
    {
        printf("\n\n");

        for (j = i+1; j< n; j++)
        {
            printf("a[%d] & a[%d](i=%d j=%d) ", i, j, i, j);
            if (a[i] > a[j]) 
            {
                tmp = a[i];
                a[i] = a[j];
                a[j] = tmp;
                printf("swap ");
            }
            print_ary( a, n );
        }
    }
}

int main( int argc, char ** argv )
{

    int *pary = NULL;

    if (argc !=2)
    {
        printf("\nUsage: %s Number\n", argv[0]); 
        return -1;
    }

    create_rondom_number(&pary, (unsigned int)atoi(argv[1]));    


    printf("\n\nrandom number: ");
    print_ary( pary, (unsigned int)atoi(argv[1]) );

    printf("Start sortting: \n");
    bubble_sort( pary, (unsigned int)atoi(argv[1]));

    printf("\n\nafter sorted: ");
    print_ary( pary, (unsigned int)atoi(argv[1]) );

    
    return 0;
}


运行结果:

[root@localhost sort]# ./bubble1 5


random number: 1 4 2 4 1
Start sortting:


a[0] & a[1](i=0 j=1) 1 4 2 4 1
a[0] & a[2](i=0 j=2) 1 4 2 4 1
a[0] & a[3](i=0 j=3) 1 4 2 4 1
a[0] & a[4](i=0 j=4) 1 4 2 4 1


a[1] & a[2](i=1 j=2) swap 1 2 4 4 1
a[1] & a[3](i=1 j=3) 1 2 4 4 1
a[1] & a[4](i=1 j=4) swap 1 1 4 4 2


a[2] & a[3](i=2 j=3) 1 1 4 4 2
a[2] & a[4](i=2 j=4) swap 1 1 2 4 4


a[3] & a[4](i=3 j=4) 1 1 2 4 4


after sorted: 1 1 2 4 4
[root@localhost sort]#

4. 

i∈[N-1,0)               //从后往前循环N-2遍

 j∈(i-1,0]            //每遍循环要处理的无序部分
swap(i,j)          //从最后一个元素开始与前边所有元素两两比较,接着倒数第二元素与前边所有元素两两比较,以此类推。即将最大(或者最小)的元素放到第最后一个位置,第二大(或第二小)的元素放到倒数第二个位置上,以此类推

 

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

void print_ary( int * ary, unsigned int len )
{
    while( len-- > 0 ) {
        printf("%d ", *ary++ );    
    }
    putchar('\n');
}

void create_rondom_number(int **parray, unsigned int number)
{
    //struct timeval tpstart;//for linux
    unsigned int i =0;

    if (NULL != *parray)
    {
        return;
    }

    *parray = (int *)malloc(sizeof(unsigned int) * number);
    (void)memset(*parray, 0, sizeof(unsigned int) * number);
    
    //gettimeofday(&tpstart,NULL); //for linux

    srand(time(NULL));//standard c
    //srandom(time(NULL));//for linux
    //srandom(tpstart.tv_usec);//for linux

    for (i=0; i<number; ++i)
    {
        (*parray)[i] = rand()%number; // range is [0, number-1] //standard c
        //(*parray)[i] = random()%number; // range is [0, number-1]//for linux 
        //(*parray)[i] = random()%(b-a) + a; //range is [a, b)//for linux
        //((*parray)[i] = 1 + (int) ((double)number * rand() / (RAND_MAX + 1.0))); // [1, number]//for linux
    }
}
/*
i∈[N-1,0)     //从后往前循环N-2遍
 j∈(i-1,0]     //每遍循环要处理的无序部分
swap(i,j)    //从最后一个元素开始与前边所有元素两两比较,
                接着倒数第二元素与前边所有元素两两比较,以此类推。
	       即将最大(或者最小)的元素放到第最后一个位置,
       	   第二大(或第二小)的元素放到倒数第二个位置上,以此类推
 */
void bubble_sort(int *a, int n)
{
    int i;
    int j;
    int tmp;

    for (i=n-1; i > 0; --i)
    {
        printf("\n\n");

        for (j=i-1; j>=0; --j)
        {
            printf("a[%d] & a[%d](i=%d j=%d) ", i, j, i, j);
            if (a[i] > a[j]) 
            {
                tmp = a[i];
                a[i] = a[j];
                a[j] = tmp;
                printf("swap ");
            }
            print_ary( a, n );
        }
    }
}

int main( int argc, char ** argv )
{

    int *pary = NULL;

    if (argc !=2)
    {
        printf("\nUsage: %s Number\n", argv[0]); 
        return -1;
    }

    create_rondom_number(&pary, (unsigned int)atoi(argv[1]));    


    printf("\n\nrandom number: ");
    print_ary( pary, (unsigned int)atoi(argv[1]) );

    printf("Start sortting: \n");
    bubble_sort( pary, (unsigned int)atoi(argv[1]));

    printf("\n\nafter sorted: ");
    print_ary( pary, (unsigned int)atoi(argv[1]) );

    
    return 0;
}


运行结果:


random number: 0 1 2 3 0
Start sortting:


a[4] & a[3](i=4 j=3) 0 1 2 3 0
a[4] & a[2](i=4 j=2) 0 1 2 3 0
a[4] & a[1](i=4 j=1) 0 1 2 3 0
a[4] & a[0](i=4 j=0) 0 1 2 3 0


a[3] & a[2](i=3 j=2) swap 0 1 3 2 0
a[3] & a[1](i=3 j=1) swap 0 2 3 1 0
a[3] & a[0](i=3 j=0) swap 1 2 3 0 0


a[2] & a[1](i=2 j=1) swap 1 3 2 0 0
a[2] & a[0](i=2 j=0) swap 2 3 1 0 0


a[1] & a[0](i=1 j=0) swap 3 2 1 0 0


after sorted: 3 2 1 0 0

 

5.

改进的冒泡排序,原理就是进行一趟从头到尾的比较,都没有发生交换的行为(使用一个标志来记录此行为),这表示此排序已经完成了,可以省略后边的比较了

改进源码:

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

void print_ary( int * ary, unsigned int len )
{
    while( len-- > 0 ) {
        printf("%d ", *ary++ );    
    }
    putchar('\n');
}

void create_rondom_number(int **parray, unsigned int number)
{
    struct timeval tpstart;
    unsigned int i =0;

    if (NULL != *parray)
    {
        return;
    }

    *parray = (int *)malloc(sizeof(unsigned int) * number);
    (void)memset(*parray, 0, sizeof(unsigned int) * number);
    
    gettimeofday(&tpstart,NULL);

    //srandom(time(NULL));
    srandom(tpstart.tv_usec);

    for (i=0; i<number; ++i)
    {
        //(*parray)[i] = random()%number; // range is [0, number-1] 
        //(*parray)[i] = random()%(b-a) + a; //range is [a, b)
        ((*parray)[i] = 1 + (int) ((double)number * rand() / (RAND_MAX + 1.0))); // [1, number]
    }
}
/*
 *改进的冒泡排序,原理就是进行一趟从头到尾的比较,
 *都没有发生交换的行为(使用一个标志来记录此行为),这表示此排序已经完成了,可以省略后边的比较了
 */
void bubble_sort(int array[],int n)
{
    int i,j,flag,temp, counter=0;

    for(i = 0; i < n-1; i++)
    {
        flag = 1;

        printf("\n\n");

        for(j = 0; j < n-i-1; j++)
        {
            counter++;

            printf("a[%d] & a[%d](i=%d, j=%d) ", j, j+1, i, j);

            if(array[j] > array[j+1])
            {
                temp= array[j];
                array[j] = array[j+1];
                array[j+1] = temp;

                flag = 0;
                printf("swap ");
            }

            print_ary( array, n );
        }

        if (1 == flag)
        {
            printf("--break from %d \n",i); //首先打印出,在第几层循环时顺序已排好
            break; //跳出循环
        }
    }

    printf("counter=%d theoretical value=%d \n", counter, (n*(n-1))/2); 

    return;
}

int main( int argc, char ** argv )
{

    int *pary = NULL;

    if (argc !=2)
    {
        printf("\nUsage: %s Number\n", argv[0]); 
        return -1;
    }

    create_rondom_number(&pary, (unsigned int)atoi(argv[1]));    


    printf("\n\nrandom number: ");
    print_ary( pary, (unsigned int)atoi(argv[1]) );

    printf("Start sortting: \n");
    bubble_sort( pary, (unsigned int)atoi(argv[1]));

    printf("\n\nafter sorted: ");
    print_ary( pary, (unsigned int)atoi(argv[1]) );

   
    return 0;
}


运行结果:

[root@localhost sort]# ./bubble2 5   


random number: 4 5 2 4 1
Start sortting:


a[0] & a[1](i=0, j=0) 4 5 2 4 1
a[1] & a[2](i=0, j=1) swap 4 2 5 4 1
a[2] & a[3](i=0, j=2) swap 4 2 4 5 1
a[3] & a[4](i=0, j=3) swap 4 2 4 1 5


a[0] & a[1](i=1, j=0) swap 2 4 4 1 5
a[1] & a[2](i=1, j=1) 2 4 4 1 5
a[2] & a[3](i=1, j=2) swap 2 4 1 4 5


a[0] & a[1](i=2, j=0) 2 4 1 4 5
a[1] & a[2](i=2, j=1) swap 2 1 4 4 5


a[0] & a[1](i=3, j=0) swap 1 2 4 4 5
counter=10 theoretical value=10


after sorted: 1 2 4 4 5
[root@localhost sort]#


参考:

http://zh.wikipedia.org/wiki/%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F

http://baike.baidu.com/view/1313793.htm
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值