【算法学习】排序
1.【算法学习】排序
2.【算法学习】Manacher 马拉车3.【算法学习】KMP 算法4.LCA 最近公共祖先(树链和倍增)这次真有树链了!!!5.线段覆盖问题6.【算法学习】学换根dp有感7.二分图最大匹配8.【算法学习】01BFS9.洛谷 P1892 [BOI2003] 团伙 种类并查集 扩展域并查集10.【算法学习】高斯消元法11.贝叶斯公式12.背包13.【算法学习】模拟退火14.【算法学习】基环树15.【算法学习】树链部分16.【算法学习】莫队17.【算法学习】分块九讲18.平衡树19.圆方树20.【算法学习】点分治21.公式22.【算法学习】笛卡尔树23.【算法学习】悬线法24.欧几里得算法与 EX25.【算法学习】逆元与求解26.【算法学习】费马定理27.三分28.裴蜀定理29.【算法学习】欧拉函数φ30.【算法学习】二维转一维问题31.【算法学习】扫描线32.【算法学习】矩阵乘法33.【算法学习】同余最短路34.【算法学习】组合数学35.【算法学习】反悔贪心排序这个东西真的挺卷的,有些就追求极致的速度,有些追求极致的简洁,有必要学一学提一提,尽管 \(sort\) 能解决绝大部分问题。
学习笔记
冒泡排序
mpft
第一个学的排序也是最简单的排序,也就是一个一个比较,如果右边的数大于左边的数就交换,我当初老师说这一个一个交换是不是就像冒泡一样,那确实哈。
#include<bits/stdc++.h> using namespace std; int n; int a[100000]; int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; } 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; }
选择排序
就如同他的名字一样,每次从剩下的区间的中选择最小的数放到区间最开始,确实挺好理解。
#include <bits/stdc++.h> using namespace std; int n; int a[1000000]; int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; } for(int i=1;i<=n;i++){ int minn=10000,id=0; for(int j=i;j<=n;j++){ if(a[j]<minn){ id=j; minn=a[j]; } } swap(a[i],a[id]); } for(int i=1;i<=n;i++){ cout<<a[i]<<" "; } return 0; }
插入排序
感觉和选择排序有点像,每个数向前找,如果比他大就交换位置,如果小就停止判断下一个数。
#include <bits/stdc++.h> using namespace std; int n; int a[1000000]; int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; } for(int i=1;i<=n;i++){ for(int j=i;j>=1;j--){ if(a[j]<a[j-1]){ swap(a[j],a[j-1]); } else{ break; } } } for(int i=1;i<=n;i++){ cout<<a[i]<<" "; } return 0; }
堆排序
用一个堆的数据结构来维护单调性,单调队列的底层原理,后来的平衡树还会再见的。
stl
#include <bits/stdc++.h> using namespace std; #define ll long long ll n; ll a[50005]; priority_queue<ll,vector<ll>,greater<ll> > q; int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; q.push(a[i]); } for(int i=1;i<=n;i++){ cout<<q.top()<<"\n"; q.pop(); } return 0; }
手写堆
#include <bits/stdc++.h> using namespace std; int n,x; int heap[1000005]; int siz=0; void up(int idx){ while(idx!=1 && heap[idx]<heap[idx/2]){ swap(heap[idx],heap[idx/2]); idx/=2; } } void add(int k){ heap[++siz]=k; up(siz); } void down(int idx){ int r=idx; if(heap[r]>heap[idx*2]&&idx*2<=siz){ r=idx*2; } if(heap[r]>heap[idx*2+1]&&idx*2+1<=siz){ r=idx*2+1; } if(r==idx){ return; } swap(heap[r],heap[idx]); down(r); } void del(){ heap[1]=heap[siz--]; down(1); } int main (){ cin>>n; while(n--){ cin>>x; if(x==1){ cin>>x; add(x); } else if(x==2){ cout<<heap[1]<<endl; } else{ del(); } } return 0; }
归并排序
分而治之好
1.逆序对
发明分治的人真是个人才,真的太厉害了,像我们的线段树最底层就是靠分治来实现的,而分治排序就更厉害了,直接把逆序对秒了。
#include<bits/stdc++.h> using namespace std; int n; int a[100005]; int b[100005]; void mergee(int l,int r){ int mid=(l+r)>>1; int lp=l,rp=mid+1,x=l;//左端到中间,中间到右端点 //x=l 为了最后修改在原数组的位置的数 while(lp <= mid && rp <= r){ if(a[lp]<=a[rp]){//左右比较 b[x++]=a[lp];//修改b lp++; } else{ b[x++]=a[rp]; rp++; } } while(lp<=mid){//左边没到中间,比已经排好的打,依次放入最后 b[x++]=a[lp]; lp++; } while(rp<=r){ b[x++]=a[rp]; rp++; } for(int i=l;i<=r;i++){//修改原数组 a[i]=b[i]; } return; } void mergesort(int l,int r){ if(l==r){//缩小到一个点返回 return; } int mid=(l+r)>>1;//分治 mergesort(l,mid);//左区间 mergesort(mid+1,r);//右区间 mergee(l,r);//合并左右区间 } int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; } mergesort(1,n); for(int i=1;i<=n;i++){ cout<<a[i]<<" "; } return 0; }
基数排序
依次对每一位进行排序,对排序后进行整理后继续对按位排序,直到全部数排完序为止。
#include<bits/stdc++.h> using namespace std; int n; int a[100005]; vector<int> v[10]; int mod=1; void solve(){ for(int i=1;i<=10;i++){ for(int j=1;j<=n;j++){ v[(a[j]/mod)%10].push_back(a[j]); } int cnt=1; for(int k=0;k<=9;k++){ for(int j=0;j<v[k].size();j++){ a[cnt++]=v[k][j]; } v[k].clear(); } mod*=10; } } int main(){ ios::sync_with_stdio(false); cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; } solve(); for(int j=1;j<=n;j++){ cout<<a[j]<<" "; } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)