又叫气泡排序,起泡排序,泡沫排序
这应该是最简单的排序算法了吧。
在未排好序以前一直扫描序列,每次将最大数的放到序列的最后,因此最多 \(n-1\) 次扫描后序列就排好序了。算法
最差时间复杂度:\(O(n ^ 2)\)
最优时间复杂度:\(O(n)\)
平均时间复杂度:\(O(n ^ 2)\)
算法是否稳定:是优化
for(int i=1;i<n;++i) {//n-1轮扫描 bool okay=true; for(int j=1;j<=n-i;++j) {//[n-i+2,n]都已经排好序了。 if(a[j]>a[j+1]) { swap(a[j],a[j+1]); okay=false; } } if(okay==true) break; }
上几张动图,帮助理解。spa
冒泡排序的一种优化,在一些特殊状况下有用。
有两种操做:code
最差时间复杂度:\(O(n ^ 2)\)
最优时间复杂度:\(O(n)\)
平均时间复杂度:\(O(n ^ 2)\)
算法是否稳定:是blog
int left=1,right=n;//[left,right]须要排序。 while(left<right) {//最多进行到left=right就中止 bool okay=true; for(int i=left;i<right;++i) {//将序列中最大的数放到最后 if(a[i]>a[i+1]) { swap(a[i],a[i+1]); okay=false; } } if(okay==true) break; --right;//[right+1,n]已经排好序了 for(int i=right;i>left;--i) { if(a[i]<a[i-1]) { swap(a[i],a[i-1]); okay=false; } } ++left;//[1,left-1]已经排好序了 if(okay==true) break; }
在未排好序以前一直扫描序列,每次将最小数的放到序列的最前,因此最多 \(n-1\) 次扫描后序列就排好序了。
与冒泡排序的不一样:冒泡排序每扫一次序列会进行屡次交换,将不符合顺序的都交换。选择排序每扫一次序列只会进行一次交换,将最小的元素与最前的元素交换。排序
最差时间复杂度\(O(n ^ 2)\)
最优时间复杂度\(O(n ^ 2)\)
平均时间复杂度\(O(n ^ 2)\)
算法是否稳定:否class
for(int i=1;i<n;++i) {//最多扫n-1次 bool okay=true; int minn=0x7fffffff,flag; for(int j=i;j<=n;++j) { if(a[j]<minn) { minn=a[j];flag=j;//找最小的并记录下位置。 okay=false; } } if(okay==true) break; std::swap(a[i],a[flag]);//将最小的元素与最前的元素交换 }
放张图理解一下效率
如{5,8,5,2,9}
,可知选择排序不稳定。基础
流程就像是打牌的摸牌阶段。im
操做将一个数插入到一个排好序的序列中时期仍然排好序便可。在序列基本有序或者序列长度小时效率很高。
最差时间复杂度:\(O(n ^ 2)\)
最优时间复杂度:\(O(n)\)
平均时间复杂度:\(O(n ^ 2)\)
算法是否稳定:是
for(int i=2;i<=n;++i) {//[1,i-1]已经排好了序 int temp=a[i],j=i-1; while(j>0&&a[j]>temp) {//将第i张牌插入其中 a[j+1]=a[j]; j--; } a[j+1]=temp; }
上张动图理解一下
在插入排序的基础上使用二分查找来肯定当前数应该插入到哪里。
这是优化吗?我为何感受比插入排序还慢。
时间复杂度:\(O(n(log n + n))\)
算法是否稳定:是否
for(int i=2;i<=n;++i) { int left=1,right=i-1,temp=a[i]; while(left<=right) {//二分查找当前数插入到哪里 int mid=(left+right)>>1; if(a[mid]>temp) right=mid-1; else left=mid+1; } for(int j=i-1;j>=left;--j) a[j+1]=a[j]; a[left]=temp;//插进去 }
对于if(a[mid]>temp) right=mid-1;
运用了插入排序,如今咱们有一个增量 \(x\) 通常为 \(\frac{n}{2}\) ,咱们按照这个份量将整个序列分红 \(x\) 组,对每组进行插入排序(由于插入排序在须要排序的序列的长度很小的时候很是快)。而后咱们将增量减少通常为 \(x = \frac{x}{2}\) (最后增量必定会变成 \(1\) ,因此是必然正确的),重复上面的步骤。虽然增量在变小,序列长度在增长,但会变得愈来愈有序,也就愈来愈高效。
又叫缩小增量排序。
最差时间复杂度:\(O(n(logn) ^ 2)\)
最优时间复杂度:\(O(n)\)
算法是否稳定:否
int ad=n/2;//增量一开始为n/2 while(ad>=1) { for(int i=1;i<=ad;++i) {//分红ad组进行插入排序 for(int j=i+ad;j<=n;j+=ad) {//插入排序 int k=j-ad,temp=a[j]; while(k>=i&&a[k]>temp) { a[k+ad]=a[k];k-=ad; } a[k+ad]=temp; } } ad=ad/2; }
以后可能会更新一下地精排序啥的,但以后再说。