Find out why have I failed!
/*
* 思考:什么叫优化,冒泡排序主要消耗时间的地方在哪里,
* 主要是在比较和交换元素,耗时操作。
* 只要减少比较和交换元素的次数就可以起到优化的作用
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
/* 普通的冒泡排序 */
void bubble_sort(int *a, int length){
for(int i=0;i<length-1;i++){
for(int j=0;j<length-i-1;j++){
if(a[j]>a[j+1]){
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
}
}
/*
* 优化1:
* 比如说一个数组,基本有序
* 初始:1,2,3,4,5,6,7,8,10,9
* 第一次排序:1,2,3,4,5,6,7,8,9,10 //比较9次,这时候数组已经有序了,
* 第二次排序:1,2,3,4,5,6,7,8,9,10 //比较8次,剩下的比较是无意义的,因为数组已经有序了
* 那么,我们是不是可以判断,当某一次循环比较结束,
* 比如说第二次排序没有交换元素的时候,说明数组已经有序了。
* 所以思路很简单:设标志位判断,如果出现某一次循环没有交换元素,则基本有序
*
*/
void bubble_sort_level1(int *a,int length){
for(int i=0;i<length-1;i++){
int flag = false; //每次进行一次循环的时候,
for(int j=0;j<length-i-1;j++){
if(a[j]>a[j+1]){
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
flag = true; //只要flag == true
}
}
if(flag == false){
break;
}
}
}
/*
* 优化2:
* 比如说一个数组,基本有序,因为是举例,都比较简单,
* 但是原理都是一样的,重要的是要学会自己思考,自己理解
* 初始:1,5,3,2,4,6,7,8,9,10
* 第一次排序:1,3,2,4,5,6,7,8,9,10 //记录最后一次交换的位置,(从0开始,下标为4,总的length长度10,)
* 第二次排序:1,2,3,4,5,6,7,8,9,10 //发现第二次排序就变成有序了,
*
*
* 这个时候,我们可以确定了,最后一次交换的位置是4,说明什么。
* 说明4之后的元素都是有序的了,冒泡排序,每次都会把最大的往最后推,
* 设置最后一个交换的位置为x,如果x < length-1,说明
* x到length-1,也就是到最后的位置基本有序。
* 所以在每次排序的时候记录最大位置下标,每次进行比较的时候,
* 后面的就不用再比了。
*
*/
void bubble_sort_level2(int *a,int length){
int lastpost = 0;
int k;
for(int i=0;i<length-1;i++){
k = length-i-1;
for(int j=0;j<k;j++){ //下一次比较到lastpos就可以
if(a[j]>a[j+1]){
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
lastpost = j; //针对上面这个情况,最后一次为4
}
}
k = lastpost; //这个时候比较到lastpos就可以
}
}
/*
* 优化3:(每次最大值,最小值,双向冒泡,也叫做鸡尾酒优化)
* 例如出现如下数组:1,2,3,4,5,6,7,0,10,9
* 使用普通冒泡,
* 第一次排序:1,2,3,4,5,6,0,7,9,10 //比较9次,交换两次,7和0交换,9和10交换
* 第二次排序:1,2,3,4,5,0,6,7,9,10 //比较8次,求出最大值不用再比,0和6交换
*
* 这个时候,我们发现了,因为只差一个最小的0元素,
* 但是后续又要进行length-i-1的比较和交换,只
* 是为了将最小值0排序到最左边,浪费了时间,所以,
* 我们可以考虑,是否可以交替进行,双向冒泡呢,即
* 第一次从最大值往前,然后再从前往后,是可以的。
*
* 使用优化的:
* 第一次排序:1,2,3,4,5,6,0,7,9,10
* 第二次排序:0,1,2,3,4,5,6,7,9,10
*
*
*/
void bubble_sort_level3(int *a, int length){
/* 切换双向排序 */
int flag = true;
int forward = 0; /* 记录正向 */
int reverse = 0; /* 记录反向 */
for(int i=0;i<length-1;i++){
if(flag){
for(int j=reverse;j<length-forward-1;j++){
if(a[j]>a[j+1]){
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
forward++;
flag = false;
}
else{
for(int j=length-forward-1;j>reverse;j--){
if(a[j-1]>a[j]){
int temp = a[j];
a[j] = a[j-1];
a[j-1] = temp;
}
}
reverse++;
flag = true;
}
}
}
/*
*
* 基本上,学习到现在,三种冒泡的优化方法以及原理都了解了,
* 最终我们可以将三种优化方法进行结合,结合写出最终的冒泡
*
* 1.是否交换元素,如果没有,提前结束,减少无意义的次数。
* 2.记录最后一次交换的下标,如果小于长度则进行替换,因为之后的比较是无意义的。
* 3.双向冒泡,防止为了只冒泡最大值,或者只冒泡最小值。
*
*/
void bubble_final_level(int *a, int length){
/* 切换双向排序 */
int flag = true;
int forward = 0; /* 记录正向 */
int reverse = 0; /* 记录反向 */
int forward_last_index = length; /* 记录正向,最后一次 */
int reverse_last_index = 0; /* 记录反向,最后一次 */
for(int i=0;i<length-1;i++){
/* 正向的正常长度 */
int forward_length = length-forward-1;
int reverse_length = reverse;
int IsExchange = false;
if(flag){
for(int j=reverse_length;j<forward_length;j++){
if(a[j]>a[j+1]){
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
IsExchange = true;
forward_last_index = j; /* 最后一次长度,如果小于forward_length */
}
}
if(IsExchange==false) /* 未交换元素,已经有序,结束 */
break;
if(forward_last_index<forward_length){ /* 则比较到forward_last_index就结束 */
forward_length = forward_last_index;
}
forward++;
flag = false;
}
else{
for(int j=forward_length;j>reverse_length;j--){
if(a[j]<a[j-1]){
int temp = a[j];
a[j] = a[j-1];
a[j-1] = temp;
IsExchange = true;
reverse_last_index = j; /* 最后一次长度,如果大于reverse_length */
}
}
if(IsExchange==false) /* 未交换元素,已经有序,结束 */
break;
if(reverse_last_index>reverse_length){
reverse_length = reverse_last_index; /* 则从reverse_last_index开始算起 */
}
reverse++;
flag = true;
}
}
}
/* 生成测试数据,写一个简单随机数生成的 */
void ProductTestData(int *p, int length){
srand((unsigned)time(NULL));
for(int i=0;i<length;i++){
p[i] = rand()%101;
}
}
void ArrayPrint(int *p,int length){
printf("show:\n");
for(int i=0;i<length;i++){
printf("%3d",p[i]);
}
printf("\n");
}
int main(){
// 生成测试数据
// int a[10000] = {0};
// ProductTestData(a,10000);
// for(int i=0;i<30;i++){
// printf("%d,",a[i]);
// }
/* 三组数据测试优化 */
int Test1[30] = {52,84,50,49,78,29,17,53,25,3,38,5,11,8,44,87,80,84,61,10,47,16,51,9,97,60,88,66,57,45};
int Test2[30] = {52,84,50,49,78,29,17,53,25,3,38,5,11,8,44,87,80,84,61,10,47,16,51,9,97,60,88,66,57,45};
int Test3[30] = {52,84,50,49,78,29,17,53,25,3,38,5,11,8,44,87,80,84,61,10,47,16,51,9,97,60,88,66,57,45};
int Test4[30] = {52,84,50,49,78,29,17,53,25,3,38,5,11,8,44,87,80,84,61,10,47,16,51,9,97,60,88,66,57,45};
int Test5[30] = {52,84,50,49,78,29,17,53,25,3,38,5,11,8,44,87,80,84,61,10,47,16,51,9,97,60,88,66,57,45};
bubble_sort(Test1,30);
bubble_sort_level1(Test2,30);
bubble_sort_level2(Test3,30);
bubble_sort_level3(Test4,30);
bubble_final_level(Test5,30);
ArrayPrint(Test1,30);
ArrayPrint(Test2,30);
ArrayPrint(Test3,30);
ArrayPrint(Test4,30);
ArrayPrint(Test5,30);
system("pause");
return 0;
}