冒泡排序
本文参考自《大话数据结构》,这本书介绍的冒泡排序让我对之前学的冒泡有了更深的理解。
冒泡排序(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)
。