【1】详解冒泡排序算法

网上都说冒泡排序很简单所以当作入门算法介绍。昨天,看某书的算法里面讲到了冒泡算法,看了一下那几行代码感觉很费解,就简单的介绍说用冒泡排序解决,代码如下,然后就是不拉不拉几行代码给出来了。可能是我理解能力差吧,昨天一直在思考这个问题,直到晚上的时候才想通,现在记下来希望对像我这种没有算法基础的人有所帮助。

假设我们有一个数组,数组元素的个数为N,那么数组元素就是arr[0]、arr[1]、arr[2]、……arr[N-2]、arr[N-1]

如果想把这个数组用冒泡排序的方法排序成从小到大的顺序,那么考虑如下代码:

1 for (j=0; j<N-1; j++)
2 {
3      if (arr[j] > arr[j+1]) 
4      {
5           tmp      = arr[j+1];
6           arr[j+1] = arr[j];
7           arr[j]   = tmp;
8      }
9  }

当按照这几行代码执行后arr[N-1]的值是最大的,但是arr[0]、arr[1]、arr[2]、……arr[N-2]这些元素的值的大小顺序我们是不知道的,我们称这是第0趟排序

再接着执行下面的代码:

1 for (j=0; j<N-2; j++)
2 {
3       if (arr[j] > arr[j+1]) 
4       {
5            tmp      = arr[j+1];
6            arr[j+1] = arr[j];
7            arr[j]   = tmp;
8       }
9 }

这几行代码执行后arr[N-2]的值是第二大的,他仅小于arr[N-1],但是arr[0]、arr[1]、arr[2]、……arr[N-3]这些元素的值的大小顺序我们是不知道的,我们称这是第1趟排序

再接着执行下面的代码:

1 for (j=0; j<N-3; j++)
2  {
3       if (arr[j] > arr[j+1]) 
4       {
5            tmp      = arr[j+1];
6            arr[j+1] = arr[j];
7            arr[j]   = tmp;
8       }
9  }

这几行代码执行后arr[N-3]的值是第三大的,他仅小于arr[N-1]和arr[N-2],但是arr[0]、arr[1]、arr[2]、……arr[N-4]这些元素的值的大小顺序我们是不知道的,我们称这是第2趟排序,可以发现每趟排序后,都有一个数组元素被排到后面,最后依次排序时的情况是:

1 for (j=0; j<1; j++)
2   {
3        if (arr[j] > arr[j+1]) 
4        {
5             tmp      = arr[j+1];
6             arr[j+1] = arr[j];
7             arr[j]   = tmp;
8        }
9 }

观察一下这几趟排序的代码会发现每趟排序时变化的只有判断循环是否结束的条件,即j<x,这个x的取值是从N-1到1,所以上面的每趟排序的代码都可以表示成:

1 for (j=0; j<x; j++)
2 {
3     if (arr[j] > arr[j+1])
4     {
5         tmp      = arr[j];
6         arr[j]   = arr[j+1];
7         arr[j+1] = tmp;
8     }
9 }

设排序的趟数是i,我们还可以发现x=N-i-1,这个关系是怎么来的呢?重新看一下上面的几趟排序过程会发现:

第0趟排序前未排序的元素有N个,已排序的元素有0个,0<=j<N-1,

第1趟排序前未排序的元素有N-1个,已排序的元素有1个,0<=j<N-2,

第2趟排序前未排序的元素有N-2个,已排序的元素有2个,0<=j<N-3,

所以,

第i趟排序前未排序的元素有N-i个,已排序的元素有i个,0<=j<N-i-1,这是因为未排序的个数加上已排序的个数的总和始终是N,而趟数和已排序的个数是相等的,每趟要排序的次数j是未排序的个数减一

所以现在的代码可以写成:

1 for (j=0; j<N-i-1; j++)
2 {
3     if (arr[j] > arr[j+1])
4     {
5         tmp      = arr[j];
6         arr[j]   = arr[j+1];
7         arr[j+1] = tmp;
8     }
9 }

好了,现在的问题就剩下如何表示需要多少趟排序了。我们知道第一趟排序时j的取值范围是0<=j<N-1,而最后一趟排序时j的取值范围是0<=j<1,所以排序的趟数i的取值范围是

0<=i<(N-1)-1+1即:0<=i<N-1,所以所有趟排序的代码可以用两个for循环表示:

 1 for (i=0; i<N-1; i++)
 2 {
 3     for (j=0; j<N-i-1; j++)
 4     {
 5         if (arr[j] > arr[j+1])
 6         {
 7             tmp      = arr[j];
 8             arr[j]   = arr[j+1];
 9             arr[j+1] = tmp;
10         }
11     }
12 }

这样我们就写出了冒泡排序的关键部分。

下面是完整的代码:

 1 #include <stdio.h>
 2 #define N 10
 3 int arr[N] = {8, 6, 78, 45, 65, 22, 13, 46, 51, 80};
 4 void BubbleSort(void);//从小到大冒泡排序
 5 void Show(void);
 6 int main(void)
 7 {
 8     printf("排序前数组是:\n");
 9     Show();
10     BubbleSort();
11     printf("排序后数组是:\n");
12     Show();
13 
14     return 0;
15 }
16 
17 void BubbleSort(void)
18 {
19     int i, j, tmp;
20     for (i=0; i<N-1; i++)
21     {
22         for (j=0; j<N-i-1; j++)
23         {
24             if (arr[j] > arr[j+1])
25             {
26                 tmp      = arr[j];
27                 arr[j]   = arr[j+1];
28                 arr[j+1] = tmp;
29             }
30         }
31     }
32 
33     return;
34 }
35 
36 void Show(void)
37 {
38     int i;
39 
40     for (i=0; i<N; i++)
41     {
42         printf("%3d", arr[i]);
43     }
44     printf("\n");
45 
46     return;
47 }

点击下载源码

如果你看完后仍有疑问可以添加我的QQ:1548253108进行详细讨论。

posted @ 2014-09-23 09:46  xxNote  阅读(261)  评论(0编辑  收藏  举报