纯手打常见基础排序
冒泡排序
相邻的比较,复合条件就交换,需要走n-1趟
时间复杂度O(n^2)
#include<bits/stdc++.h> using namespace std; const int N=10005; //核心思想: //相邻的两个比较,满足条件就交换 //从第一个元素开始,每结束一次循环就能确定一个最值 //所以需要循环n-1趟 int main(){ int n; cin>>n; int a[N]; for(int i=1;i<=n;i++) cin>>a[i]; //核心开始了 //冒泡排序,只需要走n-1趟 for(int i=1;i<n;i++) for(int j=1;j<=n-i;j++) if(a[j]>a[j+1]) swap(a[j],a[j+1]); for(int i=1;i<=n;i++) cout<<a[i]<<' '; return 0; }
选择排序
每次选出最小值放在前面
时间复杂度O(n^2)
#include<bits/stdc++.h> using namespace std; const int N=10005; //核心思想 //从第一个开始,每次选出后面最小值,然后交换 // int main(){ int n;cin>>n; int a[N]; for(int i=1;i<=n;i++) cin>>a[i]; //正式开始 //核心思想: 遍历数组,每次选出最小的放在前面 for(int i=1;i<n;i++) for(int j=i+1;j<=n;j++){ int min=i;//记录最小值下标 if(a[min]>a[j]) min=j; swap(a[i],a[min]); } for(int i=1;i<=n;i++) cout<<a[i]<<' '; return 0; }
插入排序
时间复杂度O(n^2)
#include<bits/stdc++.h> using namespace std; const int N=10005; int main(){ int n; cin>>n; int a[N]; for(int i=1;i<=n;i++) cin>>a[i]; //核心 for(int i=1;i<=n;i++){ int key=a[i]; int j=i-1; while((j>=1)&&a[j]>key){ //后移 a[j+1]=a[j]; j--; } a[j+1]=key; } for(int i=1;i<=n;i++) cout<<a[i]<<' '; return 0; }
快速排序
选出一个基数,大于基础的放右边,小于基数的放左边
快速排序的优点在于: 对于 规模大且无序 的数组具有非常高的效率
时间复杂度O(nlogn)
#include<bits/stdc++.h> using namespace std; const int N=10005; //核心思想 //选出一个基数,比基数大的放右边,小的放左边 void quick_sort(int a[],int l,int r){ //结束条件 if(l>=r) return; //在做循环的时候,要先自增,所以要先减1 int i=l-1,j=r+1,x=a[l+r>>1]; //循环结束之后, //1~~j <=a[x] // j+1~r >=a[x] while(i<j){ do{ i++; }while(a[i]<x); do{ j--; }while(a[j]>x); if(i<j) swap(a[i],a[j]); } //子问题 quick_sort(a,l,j);//左边 quick_sort(a,j+1,r);//右边 } int main(){ int n; cin>>n; int a[N]; for(int i=1;i<=n;i++) cin>>a[i]; //正式开始 quick_sort(a,1,n); for(int i=1;i<=n;i++) cout<<a[i]<<' '; return 0; }
归并排序
本质是: 两个有序数组的合并
时间复杂度 O(nlogn)
#include<bits/stdc++.h> using namespace std; //核心思想: //两个有序数组的合并 //归并排序,时间复杂度是O(nlogn),但是需要额外的内存 const int N=100005; int tmp[N]; void merge_sort(int q[], int l, int r) { if (l >= r) return; //先划分为n个独立的子序列 int mid = l + r >> 1; merge_sort(q, l, mid); merge_sort(q, mid + 1, r); int k = 0, i = l, j = mid + 1; while (i <= mid && j <= r) if (q[i] <= q[j]) tmp[k ++ ] = q[i ++ ]; else tmp[k ++ ] = q[j ++ ]; while (i <= mid) tmp[k ++ ] = q[i ++ ]; while (j <= r) tmp[k ++ ] = q[j ++ ]; for (i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j]; } int main(){ int n; cin>>n; int a[N]; for(int i=1;i<=n;i++) cin>>a[i]; merge_sort(a,1,n); for(int i=1;i<=n;i++) cout<<a[i]<<' '; return 0; }
堆排序
堆的本质就是一个完全二叉树,只不过哦满足特殊的要求
1. 大顶堆: 每一个 父节点 >= 子节点
2. 小顶堆: 每一个父节点 <= 子节点
根据这一特性,可以使用堆的性质来对元素进行排序
时间复杂度O(nlogn)
步骤:
1.从a[n/2] 到a[1] ,不断调整,每个分支结点与其孩子的值,使其满足大顶堆的性质
2.堆排序:
(1) 头尾交换 堆的长度减1
(2) 把"新堆"调整为大顶堆
(3)循环以上两步,直到只剩下对顶元素
//堆排序时间复杂度 O(nlogn) #include<bits/stdc++.h> using namespace std; const int N = 100005; int a[N]; void adjust_heap(int a[] , int i , int len){ // n/2就是父节点的坐标 , i * 2 就指向子节点 for( i = i * 2 ; i <= len ; i *= 2){ //此时i指向左孩子 if(i < len && a[i] < a[i+1])//右孩子大 i ++ ; if(a[i] > a[i/2])//如果孩子 > 父节点,则交换 swap(a[i], a[i/2]); else//父节点大于两个子节点,则不需要交换 break; } } int main(){ int n; cin >> n; for(int i = 1; i <= n; i ++) cin >> a[i] ; // 建 大顶堆, 必须从下向上 调整 // [n/2] 为最后一个分支结点(父节点) for(int i = n/2;i >= 1; i--) adjust_heap(a,i,n) ; cout << endl; //堆排序 // 堆顶 的元素 肯定是最大的,每次把堆顶的值放最后 for(int i = n; i >= 2; i--){ swap(a[1],a[i]);// 最大值已经到了最后 adjust_heap(a,1,i-1);//调整剩余n-1个 } // 输出 for(int i = 1; i <= n; i++) cout << a[i] << ' '; }
我们常用的 priority_queue的底层实现就是堆,因此可以使用priority_queue来模拟堆排序,但是效率较数组模拟较差
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现