冒泡排序
冒泡排序是一种最简单的交换排序方法,它通过两两比较相邻记录的关键字,如果发生逆序,则进行交换, 从而使用关键字小的记录如气泡一般逐渐往上“漂浮”(左移),或者使关键字大的记录如石块一样逐渐“堕落”(右移)。
算法思路
[算法步骤]
① 设待排序的记录存在数组r[1…n]中。首先将第一个记录的关键字和和第二个记录的关键字进行比较,若为逆序(既L.elem[1].key>L.elem[2].key),则交换两个记录。然后比较第二个记录和第三个记录的关键字。依次类推,直到第n-1个记录和第n个记录的关键字进行过比较为止。
上述过程成为第一趟起冒泡排序,其结果使得关键字最大的记录被安置到最后一个记录的位置上。
② 然后进行第二趟起冒泡排序,对前n-1个记录进行同样的操作,其结果是使得关键字次大的记录被安置到第n-1个纪律的位置上。
③ 重复上述比较和交换过程,第i趟是从L.elem[1]到l.elem[n-i+1]依次比较相邻两个记录的关键字,并在“逆序”时交换相邻记录,其结果是着n-i+1个记录中关键字最大的记录被交换到n-i+1的位置上。
直到在某一趟排序过程中没有进行交换记录的操作,说明序列已全部达到排序要求。
算法实现
定义存放记录的线性表结构
//记录
typedef struct ElemType{
int key;
string info;
}ElemType;
#define Maxsize 50
typedef struct {
ElemType elem[Maxsize];
int length;
}SqList;
/**
* 对顺序表L进行降序 冒泡排序
*/
void BubbleSort(SqList &L);
/**
* 对顺序表L进行升序 冒泡排序
*/
void Bubble_Sort(SqList &L);
void toString(SqList L);
void InitSqList(SqList &L);
void swap(ElemType &a, ElemType &b);
升序核心实现
void Bubble_Sort(SqList &L) {
int n = L.length;
for (int i = 0; i < n-1; i++) {
cout << " -------------------------进行 i = " << i << " 趟排序------------------------------------------------- " << endl;
bool flag = false; //表示本趟冒泡是否发生的标志
for (int j = n - 1; j > i; j--) {
//一趟冒泡过程
cout << " j = " << j;
if (L.elem[j - 1].key > L.elem[j].key) {
//若为逆序
swap(L.elem[j - 1], L.elem[j]); //交换
flag = true;
cout << " 交换: " << j-1 << "," << j;
}
cout << endl;
toString(L);
if (!flag) {
return; //若本趟遍历后没有发生交换,说明已经达到排序要求。
}
}
}
}
降序核心实现
void BubbleSort(SqList &L) {
int m = L.length - 1;
bool flag = true; //flag 用来记录某一趟排序是否发生交换
while ((m > 0) && flag) {
cout << " -------------------------剩余 m = " << m << "躺排序------------------------------------------------- " << endl;
flag = false; //置为false 如果本趟没有发生交换,则不会指向下一趟排序
for (int j = 0; j < m; j++) {
cout << " j = " << j;
if (L.elem[j].key < L.elem[j + 1].key) {
flag = true; //本趟发生了交换
swap(L.elem[j], L.elem[j + 1]); //交换
cout << " 交换: " << j << "," << j + 1;
}
cout << endl;
toString(L);
}
m--;
}
}
测试案例
void testBubbleSort() {
SqList L;
InitSqList(L);
cout <<" ----------------------------------初始 L---------------------------------------- "<< endl;
toString(L);
BubbleSort(L);
cout <<" ----------------------------------降序冒泡L---------------------------------------- "<< endl;
toString(L);
Bubble_Sort(L);
cout <<" ----------------------------------升序冒泡L---------------------------------------- "<< endl;
toString(L);
}
int main() {
testBubbleSort();
return 0;
}
测试结果
----------------------------------初始 L----------------------------------------
L.key [ 41 67 34 0 69 24 78 58 62 64 ]
-------------------------剩余 m = 9躺排序-------------------------------------------------
j = 0 交换: 0,1
L.key [ 67 41 34 0 69 24 78 58 62 64 ]
j = 1
L.key [ 67 41 34 0 69 24 78 58 62 64 ]
j = 2
L.key [ 67 41 34 0 69 24 78 58 62 64 ]
j = 3 交换: 3,4
L.key [ 67 41 34 69 0 24 78 58 62 64 ]
j = 4 交换: 4,5
L.key [ 67 41 34 69 24 0 78 58 62 64 ]
j = 5 交换: 5,6
L.key [ 67 41 34 69 24 78 0 58 62 64 ]
j = 6 交换: 6,7
L.key [ 67 41 34 69 24 78 58 0 62 64 ]
j = 7 交换: 7,8
L.key [ 67 41 34 69 24 78 58 62 0 64 ]
j = 8 交换: 8,9
L.key [ 67 41 34 69 24 78 58 62 64 0 ]
-------------------------剩余 m = 8躺排序-------------------------------------------------
j = 0
L.key [ 67 41 34 69 24 78 58 62 64 0 ]
j = 1
L.key [ 67 41 34 69 24 78 58 62 64 0 ]
j = 2 交换: 2,3
L.key [ 67 41 69 34 24 78 58 62 64 0 ]
j = 3
L.key [ 67 41 69 34 24 78 58 62 64 0 ]
j = 4 交换: 4,5
L.key [ 67 41 69 34 78 24 58 62 64 0 ]
j = 5 交换: 5,6
L.key [ 67 41 69 34 78 58 24 62 64 0 ]
j = 6 交换: 6,7
L.key [ 67 41 69 34 78 58 62 24 64 0 ]
j = 7 交换: 7,8
L.key [ 67 41 69 34 78 58 62 64 24 0 ]
-------------------------剩余 m = 7躺排序-------------------------------------------------
j = 0
L.key [ 67 41 69 34 78 58 62 64 24 0 ]
j = 1 交换: 1,2
L.key [ 67 69 41 34 78 58 62 64 24 0 ]
j = 2
L.key [ 67 69 41 34 78 58 62 64 24 0 ]
j = 3 交换: 3,4
L.key [ 67 69 41 78 34 58 62 64 24 0 ]
j = 4 交换: 4,5
L.key [ 67 69 41 78 58 34 62 64 24 0 ]
j = 5 交换: 5,6
L.key [ 67 69 41 78 58 62 34 64 24 0 ]
j = 6 交换: 6,7
L.key [ 67 69 41 78 58 62 64 34 24 0 ]
-------------------------剩余 m = 6躺排序-------------------------------------------------
j = 0 交换: 0,1
L.key [ 69 67 41 78 58 62 64 34 24 0 ]
j = 1
L.key [ 69 67 41 78 58 62 64 34 24 0 ]
j = 2 交换: 2,3
L.key [ 69 67 78 41 58 62 64 34 24 0 ]
j = 3 交换: 3,4
L.key [ 69 67 78 58 41 62 64 34 24 0 ]
j = 4 交换: 4,5
L.key [ 69 67 78 58 62 41 64 34 24 0 ]
j = 5 交换: 5,6
L.key [ 69 67 78 58 62 64 41 34 24 0 ]
-------------------------剩余 m = 5躺排序-------------------------------------------------
j = 0
L.key [ 69 67 78 58 62 64 41 34 24 0 ]
j = 1 交换: 1,2
L.key [ 69 78 67 58 62 64 41 34 24 0 ]
j = 2
L.key [ 69 78 67 58 62 64 41 34 24 0 ]
j = 3 交换: 3,4
L.key [ 69 78 67 62 58 64 41 34 24 0 ]
j = 4 交换: 4,5
L.key [ 69 78 67 62 64 58 41 34 24 0 ]
-------------------------剩余 m = 4躺排序-------------------------------------------------
j = 0 交换: 0,1
L.key [ 78 69 67 62 64 58 41 34 24 0 ]
j = 1
L.key [ 78 69 67 62 64 58 41 34 24 0 ]
j = 2
L.key [ 78 69 67 62 64 58 41 34 24 0 ]
j = 3 交换: 3,4
L.key [ 78 69 67 64 62 58 41 34 24 0 ]
-------------------------剩余 m = 3躺排序-------------------------------------------------
j = 0
L.key [ 78 69 67 64 62 58 41 34 24 0 ]
j = 1
L.key [ 78 69 67 64 62 58 41 34 24 0 ]
j = 2
L.key [ 78 69 67 64 62 58 41 34 24 0 ]
----------------------------------降序冒泡L----------------------------------------
L.key [ 78 69 67 64 62 58 41 34 24 0 ]
-------------------------进行 i = 0 趟排序-------------------------------------------------
j = 9 交换: 8,9
L.key [ 78 69 67 64 62 58 41 34 0 24 ]
j = 8 交换: 7,8
L.key [ 78 69 67 64 62 58 41 0 34 24 ]
j = 7 交换: 6,7
L.key [ 78 69 67 64 62 58 0 41 34 24 ]
j = 6 交换: 5,6
L.key [ 78 69 67 64 62 0 58 41 34 24 ]
j = 5 交换: 4,5
L.key [ 78 69 67 64 0 62 58 41 34 24 ]
j = 4 交换: 3,4
L.key [ 78 69 67 0 64 62 58 41 34 24 ]
j = 3 交换: 2,3
L.key [ 78 69 0 67 64 62 58 41 34 24 ]
j = 2 交换: 1,2
L.key [ 78 0 69 67 64 62 58 41 34 24 ]
j = 1 交换: 0,1
L.key [ 0 78 69 67 64 62 58 41 34 24 ]
-------------------------进行 i = 1 趟排序-------------------------------------------------
j = 9 交换: 8,9
L.key [ 0 78 69 67 64 62 58 41 24 34 ]
j = 8 交换: 7,8
L.key [ 0 78 69 67 64 62 58 24 41 34 ]
j = 7 交换: 6,7
L.key [ 0 78 69 67 64 62 24 58 41 34 ]
j = 6 交换: 5,6
L.key [ 0 78 69 67 64 24 62 58 41 34 ]
j = 5 交换: 4,5
L.key [ 0 78 69 67 24 64 62 58 41 34 ]
j = 4 交换: 3,4
L.key [ 0 78 69 24 67 64 62 58 41 34 ]
j = 3 交换: 2,3
L.key [ 0 78 24 69 67 64 62 58 41 34 ]
j = 2 交换: 1,2
L.key [ 0 24 78 69 67 64 62 58 41 34 ]
-------------------------进行 i = 2 趟排序-------------------------------------------------
j = 9 交换: 8,9
L.key [ 0 24 78 69 67 64 62 58 34 41 ]
j = 8 交换: 7,8
L.key [ 0 24 78 69 67 64 62 34 58 41 ]
j = 7 交换: 6,7
L.key [ 0 24 78 69 67 64 34 62 58 41 ]
j = 6 交换: 5,6
L.key [ 0 24 78 69 67 34 64 62 58 41 ]
j = 5 交换: 4,5
L.key [ 0 24 78 69 34 67 64 62 58 41 ]
j = 4 交换: 3,4
L.key [ 0 24 78 34 69 67 64 62 58 41 ]
j = 3 交换: 2,3
L.key [ 0 24 34 78 69 67 64 62 58 41 ]
-------------------------进行 i = 3 趟排序-------------------------------------------------
j = 9 交换: 8,9
L.key [ 0 24 34 78 69 67 64 62 41 58 ]
j = 8 交换: 7,8
L.key [ 0 24 34 78 69 67 64 41 62 58 ]
j = 7 交换: 6,7
L.key [ 0 24 34 78 69 67 41 64 62 58 ]
j = 6 交换: 5,6
L.key [ 0 24 34 78 69 41 67 64 62 58 ]
j = 5 交换: 4,5
L.key [ 0 24 34 78 41 69 67 64 62 58 ]
j = 4 交换: 3,4
L.key [ 0 24 34 41 78 69 67 64 62 58 ]
-------------------------进行 i = 4 趟排序-------------------------------------------------
j = 9 交换: 8,9
L.key [ 0 24 34 41 78 69 67 64 58 62 ]
j = 8 交换: 7,8
L.key [ 0 24 34 41 78 69 67 58 64 62 ]
j = 7 交换: 6,7
L.key [ 0 24 34 41 78 69 58 67 64 62 ]
j = 6 交换: 5,6
L.key [ 0 24 34 41 78 58 69 67 64 62 ]
j = 5 交换: 4,5
L.key [ 0 24 34 41 58 78 69 67 64 62 ]
-------------------------进行 i = 5 趟排序-------------------------------------------------
j = 9 交换: 8,9
L.key [ 0 24 34 41 58 78 69 67 62 64 ]
j = 8 交换: 7,8
L.key [ 0 24 34 41 58 78 69 62 67 64 ]
j = 7 交换: 6,7
L.key [ 0 24 34 41 58 78 62 69 67 64 ]
j = 6 交换: 5,6
L.key [ 0 24 34 41 58 62 78 69 67 64 ]
-------------------------进行 i = 6 趟排序-------------------------------------------------
j = 9 交换: 8,9
L.key [ 0 24 34 41 58 62 78 69 64 67 ]
j = 8 交换: 7,8
L.key [ 0 24 34 41 58 62 78 64 69 67 ]
j = 7 交换: 6,7
L.key [ 0 24 34 41 58 62 64 78 69 67 ]
-------------------------进行 i = 7 趟排序-------------------------------------------------
j = 9 交换: 8,9
L.key [ 0 24 34 41 58 62 64 78 67 69 ]
j = 8 交换: 7,8
L.key [ 0 24 34 41 58 62 64 67 78 69 ]
-------------------------进行 i = 8 趟排序-------------------------------------------------
j = 9 交换: 8,9
L.key [ 0 24 34 41 58 62 64 67 69 78 ]
----------------------------------升序冒泡L----------------------------------------
L.key [ 0 24 34 41 58 62 64 67 69 78 ]
进程已结束,退出代码0
算法分析
① 时间复杂度:
- 最好情况:初始正序,进行一趟排序,在排序过程中进行n-1次关键字对比,且不移动记录。
- 最坏情况:初始逆序,进行n-1趟排序,总的关键字对比次数KCN和记录移动次数RMN(每次交换都需要移动3次记录)分别为:
(n-1)+(n-2)+…(3-1)+(2-1) = n ( n − 1 ) 2 \frac{n(n-1)}{2} 2n(n−1)
KCN ≈ n 2 2 \frac{n^2}{2} 2n2
3[(n-1)+(n-2)+…(3-1)+(2-1)] = 3 [ n ( n − 1 ) 2 ] 3[\frac{n(n-1)}{2}] 3[2n(n−1)]
RMN ≈ 3 n 2 2 3 \frac{n^2}{2} 32n2
时间复杂度O(n^2)② 空间复杂度
冒泡排序只有在两个记录交换位置时,才需要一个辅助空间用作暂存记录,所以空间复杂度为O(1).
[算法特点]
① 稳定排序
② 可用于链式存储结构
③ 移动记录次数比较多,算法平均时间性能比直接插入排序差。当初始记录无序,n比较大时,此算法不宜采用。