Definition
交换排序
通过对比两个元素的关键字,对患者两个记录在序列中的位置,这样的排序称为交换排序
冒泡排序
从后往前扫描,每次都和这个元素相邻的前一个元素进行比较,如果小于前面的元素,则两个元素交换位置,直到扫描到序列的开头为止,每次确定一个最小的元素,最终得到一个有序序列。这样的从尾到当前确定的第 k k k 个最小元素的位置 i = k − 1 i=k-1 i=k−1 的一次扫描,称为一趟冒泡排序。对一个长度为 n n n 的序列来说,总共需要 n − 1 n-1 n−1 趟扫描得到一个有序的序列,每次扫描的平均复杂度为 n / 2 n/2 n/2,显然这是一个时间复杂度为 O ( n 2 ) O(n^{2}) O(n2) 的算法
Implementation
void bubble(ElementType* seq, int n){
for(int i = 0;i < n - 1;i++){
bool isSwap = false;
for(int j = n - 1;j > i;j--){
if(seq[j] < seq[j - 1]){
swap(seq[j], seq[j - 1]);
isSwap = true;
}
}
if(!isSwap){
// no swap happened, that is, sequence already in order
return;
}
}
return;
}
Performance
关于冒泡排序的性能:
- 时间复杂度: O ( n 2 ) O(n^{2}) O(n2)
- 空间复杂度:仅适用了常数个辅助单元, O ( 1 ) O(1) O(1)
- 稳定性:当遇到前面的元素和当前元素相等时,由于我们进行的交换的判断中当且仅当严格小于的时候进行交换,因此不会改变相等元素的相对次序,所以冒泡排序是一个稳定的排序算法
Moreover
双向冒泡排序
即从正反两个方向来进行冒泡,也就是:每次确定的除了最小的元素放在扫描区间的第一个位置之外,还会将最大的元素放在扫描区间的最后一个位置。每次进行两趟:
- 第一趟将最小的元素放在最前面
- 第二趟将最大的元素放在最后面
这时,我们每次都会在头尾确定一个元素,这样的话,我们下一次只需要扫描中间的 n − 2 i n-2i n−2i 个元素即可:
void debubble(ElementType* seq, int n){
for(int i = 0;i < n/2;i++){
bool isSwap = false;
for(int j = n - 1 - i;j > i;j--){
if(seq[j] < seq[j - 1]){
swap(seq[j], seq[j - 1]);
isSwap = true;
}
}
if(!isSwap){
return;
}
isSwap = false;
for(int j = i;j < n - 1 - i;j++){
if(seq[j] > seq[j + 1]){
swap(seq[j], seq[j + 1]);
isSwap = true;
}
}
if(!isSwap){
return;
}
}