算法 十大基本排序算法
1. 优化冒泡排序 O(n2)
算法描述:两两比较,将较小的数字置前,逐一替换;
算法优化点:使用flag来判断是否使用了swap交换,若本身有序则直接break;
算法分析:稳定,但慢,每次只能移动相邻两个数据。
动图演示:
代码:
1 void bubble_sort(vector <int> &q){ 2 for ( int i = q.size() - 1; i > 0; i --){ 3 bool flag = false; 4 for ( int j = 0; j + 1 <= i; j ++) 5 if ( q[j] > q[j + 1]){ 6 swap(q[j], q[j + 1]); 7 flag = true; 8 } 9 if (!flag) break; 10 } 11 }
2. 选择排序 O(n2)
算法描述:从头开始,选择无序区最小的数置入有序区;
算法分析:表现稳定,不占用额外内存空间,但比较次数多。
动图演示:
代码:
1 void selection_sort(vector<int> &q){ 2 for ( int i = 0; i < q.size(); i ++) 3 for ( int j = i + 1; j < q.size(); j ++){ 4 if (q[j] < q[i]) swap(q[j],q[i]); 5 } 6 }
3. 插入排序 O(n2)
算法描述:取出扫描元素与有序区比较,将小于数置后,按位移动;
算法分析:稳定,快,但比较次数不一定,比较次数越少,插入点后的数据移动越多,特别是当数据总量庞大的时候,但用链表可以解决。
动图演示:
代码:
1 void insertion_sort(vector<int> &q){ 2 for ( int i = 1; i < q.size(); i ++){ 3 int t = q[i], j; 4 for( j = i - 1; j >= 0; j --){ 5 if( t < q[j] ) q[j + 1] = q[j]; 6 else break; 7 } 8 q[j + 1] = t; 9 } 10 }
4. 希尔排序 O(n1.3)
算法描述:首先取一增量d(d<n),将a[1]、a[1+d]、a[1+2d]……列为第一组,a[2]、a[2+d]、 a[2+2d]……列为第二组……,a[d]、a[2d]、a[3d]……列为最后一组以次类推,在各组内用插入排序,然后取d'<d,重复上述操 作,直到d=1。
算法分析:快,数据移动少,但不稳定,d的取值是多少,应取多少个不同的值,都无法确切直达,只能凭经验来取。
动图演示:
5. 归并排序 O(nlog2n)
算法描述:将一个数组分为两部分,进行分别排序,后再相互比较,得出最终有序数组。
算法分析:快,无论情况如何,时间复杂度均是O(nlog2n),但若数据节点数据量大,则不合适。
动图演示:
代码:
1 void merge_sort(vector<int> &q, int l, int r){ 2 if (l >= r) return; 3 4 int mid = (l + r) >> 1; 5 merge_sort(q, l, mid); 6 merge_sort(q, mid + 1, r); 7 8 static vector<int> w; 9 w.clear(); 10 11 int i = l, j = mid + 1; 12 while (i <= mid && j <= r) 13 if(q[i] <= q[j]) w.push_back(q[i ++]); 14 else w.push_back(q[j ++]); 15 16 while (i <= mid) w.push_back(q[i ++]); 17 while (j <= r) w.push_back(q[j ++]); 18 19 for(i = l, j = 0; j < w.size(); i ++, j ++) q[i] = w[j]; 20 }
6. 快速排序 O(nlog2n)
算法描述:选择一个基准,将较小的放置左边,大的放置右边,再使用递归把小雨的子数列和大于的子数列进行排序。
算法分析:不稳定快,数据移动少,但不稳定
动图演示:
代码:
1 void quick_sort(vector<int> &q, int l, int r){ 2 if (l >= r) return; 3 int i = l - 1, j= r + 1, x = q[l + r >> 1]; 4 while(i < j){ 5 do j --; while (q[j] > x); 6 do i ++; while (q[i] < x); 7 if (i < j) swap(q[i],q[j]); 8 else quick_sort(q, l, j), quick_sort(q, j + 1, r); 9 } 10 }
7. 堆排序 O(nlog2n)
算法描述:将初始待排序序列(R1,R2….Rn)构建成大顶堆,将堆顶元素R(1)与末尾元素R(n)交换,将其置入有序区,后再将新堆(R1,R2….Rn-1)调整为大顶堆,后再重复上述步骤,直至有序区元素个数为n-1.
算法分析:不稳定,复杂。
动图演示:
8. 计数排序 O(n+k)
算法描述:将无序数组中的每个数 i 都放入数组C[ i ]中,并对所有数字进行累加,后从数组中按序输出。
算法分析:稳定,时间快。适用于k不是很大且比较集中。
动图演示:
9. 桶排序 O(n)
算法描述:设置一个定量的数组当作空桶;便理输入数据,并发数据一个一个放入桶中,对每个非空桶进行排序,并完成拼接。
算法分析:最好情况下使用线性时间O(n),桶排序的时间复杂度,取决与对各个桶之间数据进行排序的时间复杂度,显然,桶划分越小,各个桶之间的数据越少,排序越快,但相应的空间消耗会增大。
图片演示:
10. 基数排序 O(n+k)
算法描述:先取得数组中的最大数,并取得位数,后使原始数组从最低位取每个位组成的radix数组,并对radix进行计数排序。
算法分析:基数排序基于分别排序,分别收集,所以是稳定的。但基数排序的性能比桶排序要略差,每一次关键字的桶分配都需要O(n)的时间复杂度,而且分配之后得到新的关键字序列又需要O(n)的时间复杂度。假如待排数据可以分为d个关键字,则基数排序的时间复杂度将是O(d*2n) ,当然d要远远小于n,因此基本上还是线性级别的。基数排序的空间复杂度为O(n+k),其中k为桶的数量。一般来说n>>k,因此额外空间需要大概n个左右。
动图演示:
部分内容及动画演示参考:https://www.cnblogs.com/onepixel/articles/7674659.html
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步