冒泡排序算法顾名思义,经过每一次排序算法之后,最大的泡泡(数)会飘到最上面,第二次排序之后,第二大的泡泡(数)飘到倒数第二的位置 ..... 以此类推,直至完成从小到大的排序。
冒泡排序原理:
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
用图片表示冒泡排序的过程更直观:
依照冒泡排序的概念可以方便的写出排序的实现:
- (void)bubbleSort:(NSMutableArray *)arr {
int count = 0;
int cycleCount = 0;
for (int i = 0; i<arr.count-1; i++) {
cycleCount += 1;
// 每次循环都不需要比较最后一个,倒数第二个,倒数第三个... 所以二层循环最好减去已经排好序的数
for (int j = 0; j<arr.count-i-1; j++) {
cycleCount += 1;
if ([arr[j] integerValue] > [arr[j+1] integerValue]) {
NSInteger temp = [arr[j] integerValue];
arr[j] = arr[j+1];
arr[j+1] = @(temp);
count += 1;
}
}
}
NSLog(@"交换次数-->%@",@(count));
NSLog(@"循环次数-->%@",@(cycleCount));
NSLog(@"%@",arr);
}
上面的方式是最原始的排序,再次基础上可以对冒泡排序进行优化 。
冒泡排序的主要操作就是不断的循环比较然后交换两个大小不同的数的位置。 如果要正确的排序交换的次数肯定是固定的,这个是不能减少的,那就从循环比较上进行优化 。
用一个变量进行记录,记录在一次循环中是否发生了交换,如果没有则说明这个序列已经是有序的了,则退出循环。
- (void)bubbleSort:(NSMutableArray *)arr {
int count = 0;
int cycleCount = 0;
for (int i = 0; i<arr.count-1; i++) {
cycleCount += 1;
finished = YES;
for (int j = 0; j<arr.count-i-1; j++) {
cycleCount += 1;
if ([arr[j] integerValue] > [arr[j+1] integerValue]) {
NSInteger temp = [arr[j] integerValue];
arr[j] = arr[j+1];
arr[j+1] = @(temp);
finished = NO;
count += 1;
}
}
if (finished) break;
}
NSLog(@"----交换次数为%@",@(count));
NSLog(@"----循环次数为%@",@(cycleCount));
NSLog(@"%@",arr);
}
仔细研究冒泡排序的原理可以发现,还可以再次基础上进行优化。 记录每一次内层循环排序最后发生位置交换的位置K,这个位置之后的都已经是有序的了,下次排序内层循环只需要排序前 0--K 个数即可 。
- (void)bubbleSort3:(NSMutableArray *)arr {
int count = 0;
int cycleCount = 0;
int pos = (int)arr.count-1;
for (int i = 0; i<arr.count-1; i++) {
finished = YES;
cycleCount += 1;
int currentPos = 0;
// 从上一次发生交换的位置开始循环
for (int j = 0; j<pos; j++) {
cycleCount += 1;
if ([arr[j] integerValue] > [arr[j+1] integerValue]) {
NSInteger temp = [arr[j] integerValue];
arr[j] = arr[j+1];
arr[j+1] = @(temp);
count += 1;
// 记录发生交换的位置
currentPos = j;
finished = NO;
}
}
pos = currentPos;
if (finished) break;
}
NSLog(@"交换次数-->%@",@(count));
NSLog(@"循环次数-->%@",@(cycleCount));
NSLog(@"%@",arr);
}
时间复杂度:
冒泡排序需要进行两层循环,最坏的情况是:序列正好是倒序的,这种情况是O(n²),最好的情况是:序列正好的是正序的,这种情况是:O(n) .平均时间复杂度是O(n²)。
由于时间复杂度是平方级的,所以冒泡排序一般适用于小序列排序 。序列小(如:长度在20个以内)的情况下冒泡排序是比快排的速度还要快的。