冒泡排序理解与算法优化
冒泡排序为基本内部排序算法(即不借助外部空间,内部自我排序),
如上图,冒泡排序经过不断比较相邻的元素的值,进行交换,第一次从第一个元素到最后一个元素的交换,会将该数组的最大值交换到最后一项,以此循环,我们不断地找出剩余元素中的最大值,并将该最大值移动到剩余元素中的最大值.最终排序成功,本文采取从小到大排序.
(本文中语言使用c语言,算法利用函数实现,编译器参考DEV C++)
void Bubble_sort(int *a,int len)//函数传递数组名字以及数组长度
{ int i,j,k;
int temp;// 采用中间变量法
for(i=0;i<len;i++){
for(j=0;j<len-i-1;j++){//剩余元素的最大值是不断向前移动
if(a[j]<a[j+1]){
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}}
如上图:最基本的冒泡排序.
思考一:如果中间一次排序成功,那么后面就没有必要进行比较,我们可以定义一个变量,如果没有进行交换,那么排序结束,即排序成功.
代码如下
void Bubble_sort(int *a,int len)//函数传递数组名字以及数组长度
{ int i,j,k;
int temp;// 采用中间变量法
int change=1;
for(i=0;i<len&&change;i++){//进行交换后才进行下一次循环
change=0;//change被赋值为0
for(j=0;j<len-i-1;j++){
if(a[j]<a[j+1]){
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
change=1;
}
}
}}
思考二:上述排序可不可以再优化一下呢?
如果中间的某一次排序恰好使得后面的数字有序,那么我们就不需要再对这些有序的数字进行排序,那么如何才能实现这个功能呢?
可以通过记录上一次最后一次交换的位置,下一次排序从第一个比较到上次记录的位置,即设置结界边界.
代码如下:
void Bubble_sort(int *a,int len)//函数传递数组名字以及数组长度
{ int i,j,k;
int temp;// 采用中间变量法
int change=1,k=size-1,pos;//pos记录当前边界.
for(i=0;i<len&&change;i++){//进行交换后才进行下一次循环
change=0;//change被赋值为0
for(j=0;j<k;j++){
if(a[j]<a[j+1]){
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
change=1;
pos=j;
}
}
k=pos;//改变当前结界
}}
思考三:上述冒泡排序还能再优化吗?
当然可以,考虑双向冒泡排序(又称鸡尾酒排序),即每一次外层循环,内层循环进行从左向右和从右向左的排序.并且该双向排序都采用思考一与思考二的优化方式.
冒泡最终优化代码如下:
void Bubble_sort(int *a,int len){
int i,j,k,maxindex,minindex,index1=len-1,index2,judgement=1,temp;
// i,j,k用来控制循环次数,maxindex,minindex为双向排序的正向结界边界与逆向结界边界,
for(i=0;i<len-1&&judgement;i++){
judgement=0;
for(j=0;j<index1;j++){
if(a[j]>a[j+1]){
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
judgement=1;
maxindex=j;
}
}
index1=maxindex;//正向排序结界
for(j=index1;j>minindex;j--){
if(a[j]<a[j-1]){
temp=a[j];
a[j]=a[j-1];
a[j-1]=temp;
judgement=1;
index2=j;
}
}
minindex=index2;
}
minindex++;//剩余元素的最小值是不断地向后移动,所以minindex++.
}
上述即为冒泡排序的个人理解与优化.
思考:可以看到冒泡排序的基本思想就是不断地比较和交换,各类优化也只是在减少不必要的交换次数或者是比较次数.双向排序也可以大大减少排序所需时间,但在处理一些较大数据时,冒泡排序的性能远达不到要求.
这里引用一句话: