冒泡排序
本文参考自《大话数据结构》,这本书介绍的冒泡排序让我对之前学的冒泡有了更深的理解。
冒泡排序(Bubble Sort)一种交换排序,基本思想:两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止 。
交换函数
/* 交换值 */
void swap(SqList* L, int i, int j){
int temp = L->r[i];
L->r[i] = L->r[j];
L->r[j] = temp;
}
1.0版本
/* 顺序表L冒泡排序1.0 */
void BubbleSort1(SqList *L){
int i, j;
for(i=1;i<L->length;i++){ //交换的位置1
for(j=i+1;j<=L->length;j++){ //交换的位置2
if(L->r[i] > L->r[j])
swap(L, i , j); //交换值
}
}
}
2.0版本
/* 顺序表L冒泡排序2.0 */
void BubbleSort2(SqList *L){
int i, j;
for(i=1;i<L->length;i++){ //循环的次数=数组长度-1,因为最后一次只剩一个元素,不需要判断
for(j=L->length-1;j>=i;j--){ //冒泡:每次都与后一个比较,如果当前的比后一个大,则交换。即小的放前面
if(L->r[j] > L->r[j+1]
swap(L, j, j+1);
}
}
}
1.0与2.0区别
1.0和2.0的区别在于:1.0不是真冒泡,它采用的是,每次拿去跟r[i] (i=1,2,…,n)做比较,这样做有什么问题呢?
比如,当序列为94563,i=1,2时,
- 1.0排序的最终结果为:39564,34956,此时移动次数为:2,3;
- 2.0排序的最终结果为:39456,34956,此时移动次数为:4,1;
- 可以不一样的地方在于,如果序列本身是部分有序的,那么2.0版本的移动次数会少很多(第1次和第2次对比),而且2.0不会将已经部分排好序的序列再次打乱。
3.0版本
/* 顺序表L冒泡排序3.0 */
void BubbleSort3(SqList *L){
int i, j;
Status flag = TRUE; //标记
for(i=1;i<L->length && flag;i++){
flag = FALSE; //设置为false,代表没有发生数据交换,即后面的序列都是已经排好序的,后面可以跳出循环不用重复判断了
for(j = L->length-1;j>=i;i--){
if(L->r[j] > L->r[j+1]){
swap(L, j, j+1);
flag = TRUE; //如果有数据交换,则flag为true
}
}
}
}
3.0版本可以避免多次无意义的循环判断,比如序列为:123456,这种序列本身就已经排好序了,在i=1的时候就已经全部都知道了,只需遍历一次就行,后面的遍历都是没有意义的。
复杂度分析
按照3.0版本,最好的情况是表本身有序,那么比较的次数为n-1次,没有发生数据交换,时间复杂度O(n);最坏情况,排序表为逆序,此时需要比较n*(n-1)/2次,同时作等数量级的记录移动,此时时间复杂度为O(n^2)。

本文深入探讨冒泡排序,从基本的交换函数到不同版本的实现,包括1.0、2.0和3.0版本。重点分析了2.0版本如何减少不必要的交换和移动次数,以及3.0版本如何优化无意义的循环。文章最后分析了冒泡排序的时间复杂度,指出在最好和最坏情况下的复杂度分别为O(n)和O(n^2)。
39万+

被折叠的 条评论
为什么被折叠?



