冒泡排序(Bubble Sort)

17 篇文章 0 订阅

冒泡排序(Bubble Sort)


需求:实现int类型数组从小到大排序

代码(C实现):

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

/***************************************************************************
 *Function Name:bubble_sort
 *Function argt:
 *              1.int *parray:a point which point to an array;
 *              2.int num    :a var(int), size of array, in term of element;
 *Return  Value:void
 *Description  :sort an array, from small to large.
 *Author       :test1280
 *History      :2017/04/13
 **************************************************************************/
void bubble_sort(int *parray, int num)
{
    int tmp;
    int i, j;
    for (i=0; i<num-1; i++)
    {
        for (j=0; j<num-1-i; j++)
        {
            if (parray[j]>parray[j+1])
            {
                tmp = parray[j];
                parray[j] = parray[j+1];
                parray[j+1] = tmp;
            }
        }
    }
}

int main()
{
    int array[10] = {9, 5, 12, 36, 52, 1, -8, 14, -7, 0};
    bubble_sort(array, 10);
    for (int i=0; i<10; i++)
    {
        printf("%d\n", array[i]);
    }
    return 0;
}

所谓冒泡排序,就是待排序序列中每两个元素进行比较,如果满足一定条件,则进行元素之间的相互交换。

上述例子中:

待排序的元素共有10个;

第0次外循环:每两个元素进行比较,从0位置开始,比较9次,即可将最大的元素交换到最后一个位置9处;
第1次外循环:每两个元素进行比较,从0位置开始,比较8次,即可将最大的元素交换到位置8处;
第2次外循环:每两个元素进行比较,从0位置开始,比较7次,即可将最大的元素交换到位置7处;
……
共需要外循环num-1次,因为最后一个不需要比较,一定是最小的。
第i次外循环中,内循环共有num-i-1次。


上述例子的排序示意:

original:9 5 12 36 52 1 -8 14 -7 0

(以下为每次两个元素交换 的示意图,红色标记是哪两个元素交换)

外循环第0次:

内循环第0次交换:

5 9 12 36 52 1 -8 14 -7 0

内循环第1次交换:

5 9 12 36 1 52 -8 14 -7 0

内循环第2次交换:

5 9 12 36 1 -8 52 14 -7 0

内循环第3次交换:

5 9 12 36 1 -8 14 52 -7 0

内循环第4次交换:

5 9 12 36 1 -8 14 -7 52 0

内循环第5次交换:

5 9 12 36 1 -8 14 -7 0 52

外循环第0次结束。

可以看到,52这个最大的数字从左到右,一点点地浮出水面,就像泡泡一样,得名冒泡排序。

start 1
5 9 12 1 36 -8 14 -7 0 52 
5 9 12 1 -8 36 14 -7 0 52 
5 9 12 1 -8 14 36 -7 0 52 
5 9 12 1 -8 14 -7 36 0 52 
5 9 12 1 -8 14 -7 0 36 52
end 1
start 2
5 9 1 12 -8 14 -7 0 36 52 
5 9 1 -8 12 14 -7 0 36 52 
5 9 1 -8 12 -7 14 0 36 52 
5 9 1 -8 12 -7 0 14 36 52 
end 2
start 3
5 1 9 -8 12 -7 0 14 36 52 
5 1 -8 9 12 -7 0 14 36 52 
5 1 -8 9 -7 12 0 14 36 52 
5 1 -8 9 -7 0 12 14 36 52 
end 3
start 4
1 5 -8 9 -7 0 12 14 36 52 
1 -8 5 9 -7 0 12 14 36 52 
1 -8 5 -7 9 0 12 14 36 52 
1 -8 5 -7 0 9 12 14 36 52 
end 4
start 5
-8 1 5 -7 0 9 12 14 36 52 
-8 1 -7 5 0 9 12 14 36 52 
-8 1 -7 0 5 9 12 14 36 52 
end 5
start 6
-8 -7 1 0 5 9 12 14 36 52 
-8 -7 0 1 5 9 12 14 36 52 
end 6
start 7
end 7
start 8
end 8

start标记的是外循环第i次,从0开始;
start与end之间的是在此次循环中,进行了多少次内循环,输出为内循环交换后的结果。

若想要以从大到小的顺序排序,可以:

void bubble_sort(int *parray, int num)
{
    int tmp;
    int i, j;
    for (i=0; i<num-1; i++)
    {   
        printf("start %d\n", i); 
        for (j=0; j<num-1-i; j++)
        {   
            if (parray[j]<parray[j+1])
            {   
                tmp = parray[j];
                parray[j] = parray[j+1];
                parray[j+1] = tmp;
            }   
        }   
        printf("end %d\n", i); 
    }   
}

仅仅修改一下比较的条件即可:if (parray[j]<parray[j+1])

思考:

是否可以从后向前进行冒泡呢?

假设现在的需求还是从小到大,只不过要求从后进行冒泡。

我们可以每次外循环时总是将本轮中最小的放置到本轮的最前位置,代码修改如下:

void bubble_sort(int *parray, int num)
{
    int tmp;
    int i, j;
    for (i=0; i<num-1; i++)
    {   
        for (j=num-1; j>i; j--)
        {   
            if (parray[j]<parray[j-1])
            {   
                tmp = parray[j];
                parray[j] = parray[j-1];
                parray[j-1] = tmp;
            }   
        }   
    }   
}

每次交换后序列:

9 5 12 36 52 1 -8 -7 14 0 
9 5 12 36 52 -8 1 -7 14 0 
9 5 12 36 -8 52 1 -7 14 0 
9 5 12 -8 36 52 1 -7 14 0 
9 5 -8 12 36 52 1 -7 14 0 
9 -8 5 12 36 52 1 -7 14 0 
-8 9 5 12 36 52 1 -7 14 0 
-8 9 5 12 36 52 1 -7 0 14 
-8 9 5 12 36 52 -7 1 0 14 
-8 9 5 12 36 -7 52 1 0 14 
-8 9 5 12 -7 36 52 1 0 14 
-8 9 5 -7 12 36 52 1 0 14 
-8 9 -7 5 12 36 52 1 0 14 
-8 -7 9 5 12 36 52 1 0 14 
-8 -7 9 5 12 36 52 0 1 14 
-8 -7 9 5 12 36 0 52 1 14 
-8 -7 9 5 12 0 36 52 1 14 
-8 -7 9 5 0 12 36 52 1 14 
-8 -7 9 0 5 12 36 52 1 14 
-8 -7 0 9 5 12 36 52 1 14 
-8 -7 0 9 5 12 36 1 52 14 
-8 -7 0 9 5 12 1 36 52 14 
-8 -7 0 9 5 1 12 36 52 14 
-8 -7 0 9 1 5 12 36 52 14 
-8 -7 0 1 9 5 12 36 52 14 
-8 -7 0 1 9 5 12 36 14 52 
-8 -7 0 1 9 5 12 14 36 52 
-8 -7 0 1 5 9 12 14 36 52

若想从后向前冒泡,从大到小排序,只需要针对上面的比较条件改成:if (parray[j]>parray[j-1])即可:

void bubble_sort(int *parray, int num)
{
    int tmp;
    int i, j;
    for (i=0; i<num-1; i++)
    {   
        for (j=num-1; j>i; j--)
        {   
            if (parray[j]>parray[j-1])
            {   
                tmp = parray[j];
                parray[j] = parray[j-1];
                parray[j-1] = tmp;
            }   
        }   
    }   
}

嗯,看起来比较顺溜了:

1.从小到大排序,从前向后冒泡;
2.从大到小排序,从前到后冒泡;
3.从小到大排序,从后向前冒泡;
4.从大到小排序,从后向前冒泡。

1和2只是条件换了下;3和4也是条件换了下。

冒泡排序最关键的是边界值,大家有点晕的时候可以在纸上画一画,立刻就清晰了。

再思考,有没有优化版的冒泡呢?

假设现在有一个待排序数组:0, 2, 1, 3, 4, 5, 6, 7, 8, 9

如果按照我们上述的冒泡算法,执行如下:

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

void print_array(int *parray, int num)
{
    int i;
    for (i=0; i<num; i++)
    {   
        printf("%d ", parray[i]);
    }   
    printf("\n");
}

void bubble_sort(int *parray, int num)
{
    int tmp;
    int i, j;
    for (i=0; i<num-1; i++)
    {   
        printf("...start:%d\n", i); 
        for (j=0; j<num-1-i; j++)
        {   
            if (parray[j]>parray[j+1])
            {   
                tmp = parray[j];
                parray[j] = parray[j+1];
                parray[j+1] = tmp;
            }   
            print_array(parray, 10); 
        }   
        printf("...end:%d\n", i); 
    }   
}

int main()
{
    int array[10] = {0, 2, 1, 3, 4, 5, 6, 7, 8, 9}; 
    printf("ori:\n");
    print_array(array, 10);
    bubble_sort(array, 10);
    for (int i=0; i<10; i++)
    {
        printf("%d\n", array[i]);
    }
    return 0;

[test1280@localhost sort]$ ./main
ori:
0 2 1 3 4 5 6 7 8 9 
...start:0
0 2 1 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
...end:0
...start:1
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
...end:1
...start:2
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
...end:2
...start:3
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
...end:3
...start:4
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
...end:4
...start:5
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
...end:5
...start:6
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
...end:6
...start:7
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
...end:7
...start:8
0 1 2 3 4 5 6 7 8 9 
...end:8
0
1
2
3
4
5
6
7
8
9

很明显后面的循环都是不必要的,我们可以增加一个标识来记录一下:

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

void print_array(int *parray, int num)
{
    int i;
    for (i=0; i<num; i++)
    {   
        printf("%d ", parray[i]);
    }   
    printf("\n");
}

void bubble_sort(int *parray, int num)
{
    int tmp;
    int i, j;
    int flag = 1;
    for (i=0; i<num-1; i++)
    {   
        flag = 0;
        printf("...start:%d\n", i); 
        for (j=0; j<num-1-i; j++)
        {   
            if (parray[j]>parray[j+1])
            {   
                tmp = parray[j];
                parray[j] = parray[j+1];
                parray[j+1] = tmp;
                flag = 1;
            }
            print_array(parray, 10);
        }
        printf("...end:%d\n", i);
        if (flag == 0)
            break;
    }
}

int main()
{
    int array[10] = {0, 2, 1, 3, 4, 5, 6, 7, 8, 9};
    printf("ori:\n");
    print_array(array, 10);
    bubble_sort(array, 10);
    for (int i=0; i<10; i++)
    {
        printf("%d\n", array[i]);
    }
    return 0;
}

[test1280@localhost sort]$ ./main
ori:
0 2 1 3 4 5 6 7 8 9 
...start:0
0 2 1 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
...end:0
...start:1
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
...end:1
0
1
2
3
4
5
6
7
8
9
[test1280@localhost sort]$

相对最开始的冒泡排序,效率提高了一些。



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值