算法练习——冒泡排序的两次进化
来源:互联网 发布:淘宝发布话费充值 编辑:程序博客网 时间: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;
}
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;
}
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;
}
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
- 算法练习——冒泡排序的两次进化
- 排序算法自我练习(一)——冒泡排序
- [算法练习] 冒泡排序
- 算法练习---冒泡排序
- 常见的排序算法—冒泡排序
- 练习——冒泡排序
- 排序算法—冒泡排序
- 排序算法——冒泡的优化
- 三个简单的算法—冒泡排序
- 冒泡排序和快速排序算法练习
- 【排序算法】——冒泡排序算法
- [算法练习]冒泡排序的C语言实现
- 算法——冒泡排序
- 算法——冒泡排序
- 算法——冒泡排序
- 啊哈!算法—冒泡排序
- 算法之—冒泡排序
- 【算法系列】—冒泡排序
- 集成支付宝SDK时错误的解决办法
- 指针
- document.body属性[转]
- LVS+PIRANHA实现负载均衡
- 是选择abstract class 还是选择 interface这是个问题
- 算法练习——冒泡排序的两次进化
- java布局管理器总结
- 值得学习的python项目
- jQuery序列化表单成对象
- perl wantarray()
- ubuntu下apache2 php mysql 配置
- LeetCode-Maximum Subarray
- [Leetcode]Spiral Matrix
- 构造类cdib.h