算法练习——冒泡排序的两次进化

来源:互联网 发布:淘宝发布话费充值 编辑:程序博客网 时间:2024/05/22 17:42

冒泡排序是一个很简单的排序算法,也是每一个学计算机的同学一开始就能掌握的算法。冒泡排序虽然简单,但是却很简陋,是效率很低的排序算法。如果我们对其稍加改造,它还是能够变得灵活一些的。这就是这篇文章的主题,冒泡排序的改进方式。
先来看一下我们熟悉的冒泡排序(这里使用的C++编译器是Xcode,并不是兼容所有版本的,所以大家将其当作伪代码好了,,,):

//原始的bubbleSort
int bubbleSort_origin(int a[],int n)
{
    
int compareNum=0;   //元素比较次数
    
int step=0;     //趟数
    
int *b=new int[n];
    
//将数组元素拷贝到b数组里,不改动a数组
    
if(a!=NULL)
    {
        
for(int i=0;i<n;i++)
        {
            b[i]=a[i];
        }
    }
    
else
    {
        
return -1;
    }
    
for(int i=0;i<n-1;i++)
    {
        
for (int j=0;j<n-i-1; j++)
        {
            compareNum++;
            
if(b[j]>b[j+1])
            {
                
int temp=b[j+1];
                b[j+
1]=b[j];
                b[j]=temp;
            }
        }
        step++;
    }
    
int i=0;
    
for(i=0;i<n-1;i++)
    {
        
cout<<b[i]<<",";
    }
    
cout<<b[i]<<endl;
    
cout<<"元素比较的次数:"<<compareNum<<endl;
    
return step;
}

OK,我们说一下第一个问题,数据结构课一定也讲过,就是如果数组本身就已经排好了,大家都站好队了,或者才两趟就已经把队伍排好了,可是这种原始的冒泡排序还要傻傻地
继续重复着没有意义的比较,数据量多了,还是挺坑的。
插播最近我很爱的一个广告:最近我在玩一款三国策略游戏,,,,,,,,,如果你是脑残,就别来了,来了也是坑,哈哈哈哈。有时候这个广告我要看好几遍。
那么第一次进化就是为冒泡排序添加一个哨兵,它是一个bool变量,用来标记是否已经排好序了,如果排好序了,就不排下一趟了呗:
//带哨兵的冒泡排序
int bubbleSort_soilder(int a[],int n)
{
    
int compareNum=0;   //元素比较次数
    
int step=0;     //趟数
    
int *b=new int[n];
    
//将数组元素拷贝到b数组里,不改动a数组
    
if(a!=NULL)
    {
        
for(int i=0;i<n;i++)
        {
            b[i]=a[i];
        }
    }
    
else
    {
        
return -1;
    }
    
bool flag=true//这就是哨兵哥
    
for(int i=0;i<n-1&&flag;i++)
    {
        flag=
false;
        
for (int j=0;j<n-i-1; j++)
        {
            compareNum++;
            
if(b[j]>b[j+1])
            {
                
int temp=b[j+1];
                b[j+
1]=b[j];
                b[j]=temp;
                flag=
true;
            }
        }
        step++;
    }
    
int i=0;
    
for(i=0;i<n-1;i++)
    {
        
cout<<b[i]<<",";
    }
    
cout<<b[i]<<endl;
    
cout<<"元素比较的次数:"<<compareNum<<endl;
    
return step;
}

只要加一个bool flag,每一趟开始时,都判断一下flag,如果flag为true,说明上一趟还交换过元素的,队伍还不一定排好呢,如果为false,则说明上一趟都没交换过值,队伍已经排好了,已经OK了。
至于第二次进化,则在于,有哨兵的冒泡排序虽然解决了坑的不停检查已经排好队的情况,但是如果队伍是:1,1,1,1,1,1,1,1,1,1,1,1,1,100,9,10,25,33,1000,1000,1000,1000,1000    ,前后两端都已经排好了,但是中间的排列却还是要从头比较,一直比较到尾部,10个郭靖排在队头,10个姚明排在队尾,中间一拨人打乱了顺序,关前后两头啥事啊:

//自动调节比较范围的冒泡排序
int bubbleSort_final(int a[],int n)
{
    
int compareNum=0;   //元素比较次数
    
int step=0;     //趟数
    
int *b=new int[n];
    
//将数组元素拷贝到b数组里,不改动a数组
    
if(a!=NULL)
    {
        
for(int i=0;i<n;i++)
        {
            b[i]=a[i];
        }
    }
    
else
    {
        
return -1;
    }
    
    
int headindex=0;    //比较范围的头部
    
int tailindex=n-1;  //比较范围的尾部
    
bool flag=false;    //判断是否是某一趟的第一次交换元素
    
for(int i=0;i<n-1;i++)
    {
        
if(headindex>=tailindex)    //比较范围首尾会师
        {
            
break;
        }
        
int tailindex_temp=0;
        
for (int j=headindex;j<tailindex; j++)
        {
            compareNum++;
            
if(b[j]>b[j+1])
            {
                
int temp=b[j+1];
                b[j+
1]=b[j];
                b[j]=temp;
                
if(flag==false)
                {
                    headindex=j-
1?j>0:j;
                    flag=
true;
                }
                tailindex_temp=j+
1;
            }
        }
        tailindex=tailindex_temp;
        flag=
true;
        step++;
    }
    
int i=0;
    
for(i=0;i<n-1;i++)
    {
        
cout<<b[i]<<",";
    }
    
cout<<b[i]<<endl;
    
cout<<"元素比较的次数:"<<compareNum<<endl;
    
return step;
}

好了,这就是冒泡排序的两度进化,显然,一般情况下,哨兵的冒泡排序和调整范围的冒泡排序都比原始冒泡排序趟数少,比较次数则显然是调整范围的冒泡排序要少的多。那这种进化的冒泡排序降复杂度吗?sorry,不降,叔叔我们不降,还是O(n^2)........
还有,虽然命名为bubbleSort_final,但也许你还有更好的方法,所以这远不是final,,,下次遇到复杂一些的问题,一定画图辅助。。。。这是第一篇算法练习题,希望能和大家一同交流进步:)











0 0
原创粉丝点击