冒泡排序
- 主要思想
冒泡排序操作的基础为数据交换,如果相邻两个对象满足排序要求,则不作交换;否则就交换对象储存地址里面的基本内容。冒泡排序把整体数组或集合分为两部分,一部分为有序区,另外一部分则为无序区,每次操作的范围囿于在无序区,如果按照严格的冒泡排序,每次有序区域会增加一个元素,无序区会减少一个元素,直至无序区元素为空,此时所有对象都有序。
- 排序过程
假设输入数组a[]={9,16,12,3},要求用冒泡方法进行升序排列,冒泡的过程可以图表示,
第一轮过程中需要比较三次,首先用9和16进行比较,由于9和16满足升序原则,本过程不需要进行数据交换;然后用16和12比较,这时候可以发现16<12,不满足升序原则,则需要进行二者之间的数据交换,从结果上看,就是数据16代表的绿色圆泡位置上冒一位;最后本轮的最后一次比较16>3,不满足升序原则,16代表的绿泡再上升一位。
此时此刻,第一个有序区形成,虽然仅仅包含了一个元素,但它是划时代的区域,后续的这个区域会聚集越来越多的有序泡泡。
第一轮比较完成后,无序区收缩,在第二轮排序过程中,我们无需对有序区做任何操作,只需要关注无序区排序即可,用图表示冒泡过程,同理,首先比较9<12,满足升序要求,故不作任何操作;接着比较12>3,不满足升序要求,所以交换二者储存位置上的内容,这时有一个有序区诞生,结合第一轮的操作,有序区的元素增加至2个。
2轮完成后,有序区元素增加至2个,图示其清晰的界限:
我们来到最后一轮的排序,最优一轮仅剩两个元素,冒泡后结果为,新形成有序区和之前两轮有序区结合后,,呈现结果为:
最终冒泡结果:
我们看到升序冒泡,底部储存的为小泡泡,顶部储存的为大泡泡,至此,冒泡排序完成。
- 抽象过程
假定有n个对象待排序操作,操作的基础为两两比较,这样在第一轮过程中,从第一个元素开始,它实际上要不断与上一个元素比较,并根据比较结果,确定是否交换,那么n个元素两两之间的间隙就为n-1,也就是不断搜索,在 n的位置上,我们确保得到最大的泡泡。
接着再对n-1个无需元素重复此操作,直至所有元素有序。
- 分类讨论
我们有两类选择,一类是传统的代码实现方式,需要中规中矩地进行进行n*(n-1)/2次比较,比较过程中根据两者值的大小,决定是否对值进行交换。
另外一类情况是,在无序区,已经是事实上的有序排列,进行比较只是例行公事,而不需要任何交换操作,这种情况就提供了改善空间。
上述数组进行第三趟排列的时候,整体已经是有序序列,后面的比较不会产生任何交换的操作,那么如何确定需要排序的范围呢。我们可以通过保存记录,缩小比较范围或者直接停止比较,这就需要用额外的空间保存最终的状态,从而确认后续的操作状态。
- 代码实现
a.)传统的的代码实现,
void bubble_sort(int *a, int n)
{
int i;
int j;
for(i=0;i<n-1;i++)
{
for(j=0;j<n-1-i;j++)
{
if(a[j]>a[j+1])
{
swap_elements(a+j,a+j+1);
}
}
}
return;
}
void swap_elements(int *p, int *q)
{
int temp;
temp=*p;
*p=*q;
*q=temp;
return;
}
void show_sorted_array(int *a, int n)
{
int i;
for(i=0;i<n;i++)
{
printf("%d ",a[i]);
}
printf("\n");
}
b.) 改进的方法
void bubble_sort_optimization(int *a, int n)
{
int j;
int last_exchange_index;
int upper_bound;
last_exchange_index=n-1;
while(last_exchange_index!=0)
{
upper_bound=last_exchange_index;
last_exchange_index=0;
for(j=0;j<upper_bound;j++)
{
if(a[j]>a[j+1])
{
last_exchange_index=j;
swap_elements(a + j, a + j + 1);
}
}
}
return;
}
void swap_elements(int *p, int *q)
{
int temp;
temp=*p;
*p=*q;
*q=temp;
return;
}
void show_sorted_array(int *a, int n)
{
int i;
for(i=0;i<n;i++)
{
printf("%d ",a[i]);
}
printf("\n");
}
- 总结
冒泡排序属于交换排序的方法之一,对两个元素进行比较,然后决定是否交换,最终完成冒泡的排序过程。冒泡排序分为传统的冒泡和改进的冒泡方法。
另外一类交换排序方法是快速排序,它通过分而治之的方法,效率更高,是常用的排序选择方法。
参考资料: