高速排序的学习笔记
目前为止,学习的排序方法已经有很多了,
- 插入排序,
- 冒泡排序,
- 选择排序,
- 希尔排序,
- 归并排序,
- 快速排序
- 计数排序(桶排序)
- 堆排序(好像没有学过)。。
- 基数排序(好像没学过)(咕咕咕~~)
一,插入排序
核心思想:以升序排序为例,给v=a[i]作为基准数,j=i-1(保存i前一个数的下标);每次判断a[j]>v如果出现满足的情况,则说明出现了错乱,前面的数竟然比后面的数更大了。则开始进行插入步骤
具体插入的决策如下
1 ,如果a[j]>v ,{a[j+1]=a[j];j--;} //后一个数比前一个数小,那么就依次给前一个数赋值给后一个数。
2 ,如果a[j]<=v , a[j+1]=v; //后一个数不必前一个数小,那么就给v赋值给a[j+1];
3 ,如果a[j]<a[j+1],我们也直接给a[j+1]=v;,也就是不排序,自己赋值给自己;
#include<iostream> using namespace std; int a[10005]; int main() { int n; cin>>n; for(int i=0;i<n;i++)cin>>a[i]; //核心代码 for(int i=1;i<n;i++) { int v=a[i]; int j=i-1; while(j>=0&&a[j]>v) //如果j>=0,判断是否越界,以从小到大排序,那么a[j]>v判断是否发生错乱,也就是后一个数比前一个数小的情况,这样就要进行排序。 { //如果要判断从大到小排序,那么给循环条件更改一点,a[j]<v;则进行排序 a[j+1]=a[j]; j--; } a[j+1]=v; } for(int k=0;k<n;k++)cout<<a[k]<<' '; return 0; }
二,希尔排序法
希尔排序的核心思想:就是,分别以G[i] 为基准数,进行插入排序
如果有这样一个数列 a[6]={1,3,4,5,6,2};
那么数列G[]={4,1}; //大家发现了吗,G[i]数列是怎么来的?这个其实就是排序时要用到的基准数,一般是取 G{(3*m+1)|0<=m<=n},这样排序的效率最高为O(n^1.25),
那么模拟一下,根据之前算好的t[],我们分别是,每4个,每1个数字进行插入排序
第一轮排序元素=={1,5};发现是已排好序的,那么退出,
//接下来只剩下,最后的一个排序元素 ‘1’ ,这样相当于,大臣们已经给所有繁琐的任务做好啦,最后给签字留给皇帝来干也就是这个“1”....是不是很厉害!闲话少说。。
第二轮排序元素=={1,3,4,5,6,2},然后进行排序
但是一般而言,扩展开来,元素如果很多的话,那么就会有很多个区间排序。就相当于我们给很多很多的任务分发给了大臣们,如果大臣走过去一看,领地是欣欣向荣的,也就是最好的情况,已经是从小到大排序了那么我们就不需要给这一块领地投入过多的精力去治理了,也就是说,这一块领地不需要排序,省下了时间。
最后总能使得,各个大臣给他们应该左的事情做完了,最后留给皇帝“1”来签字。然后这个希尔排序就完成啦!!!核心代码如下:
#include<iostream> #include<vector> using namespace std; vector<int>G;//存放G数组 int arr[10000005]; void insertSort(int arr[],int n,int g) //大臣们分别按 G[i]进行治理领地,就是排序啦 { for(int i=g;i<n;i++) { int v=arr[i]; int j=i-g; while(j>=0&&arr[j]>v) { arr[j+g]=arr[j]; j-=g; } arr[j+g]=v; } } void ShellSort(int arr[],int n) { for(int i=G.size()-1;i>=0;--i) { insertSort(arr,n,G[i]); } } int main() { int n; cin>>n; for(int i=0;i<n;i++)cin>>arr[i]; for(int h=1;h<=n;h=3*h+1)G.push_back(h); ShellSort(arr,n); for(int i=0;i<n;i++)cout<<arr[i]<<' '; return 0; }
三、冒泡排序
核心思想:冒泡算法比较基础,就不多说了,每次比较前当前数字,是否比后面的数字大,如果大,则交换a[j]>a[j+1]如果是,则交换
#include<iostream> using namespace std; int a[105]; int main() { int n; cin>>n; for(int i=0;i<n;i++)cin>>a[i]; for(int i=0;i<n-1;i++) for(int j=0;j<n-1-i;j++) if(a[j]>a[j+1])swap(a[j],a[j+1]); for(int i=0;i<n;i++)cout<<a[i]<<' '; return 0; }
四,快速排序
核心思想:就是,分治,分割,
1,分割指的是,给一个序列,以q为基准,左边全是小于q的序列,右边全是大于q的序列,
每轮都给当前序列,分成两组,O(log2N)次之后, 那么整个序列都是从小到大的数列了
2,分治,指的的,在分割之后的基础上, 继续分割,,quickSort(arr , l, m) quickSort (arr ,m , r);
#include<iostream> #define ss second #define ff first using namespace std; pair<char,int>a[100005],b[100005]; pair<char,int>L[100005],R[100005]; const int INF=1e9+7; int Parttion(pair<char,int> a[],int l,int r) { pair<char,int>x=a[r]; int i=l-1; for(int j=l;j<r;j++)if(a[j].ss<=x.ss)swap(a[++i],a[j]); swap(a[++i],a[r]); return i; } int quickSort(pair <char ,int> a[],int l,int r) { if(l<r) { int q=Parttion(a,l,r); quickSort(a,l,q-1); quickSort(a,q+1,r); } } int main() { int n; cin>>n; for(int i=0;i<n;i++)cin>>a[i].ff>>a[i].ss,b[i]=a[i]; quickSort(a,0,n-1);for(int i=0;i<n;i++)cout<<a[i].ff<<' '<<a[i].ss<<endl; return 0; }
五,归并排序
核心思想:分治,归并
分治:每次给数列分成两半....n次过后,最后序列里都只剩下2个数字或1个数字,那么2个数字则比较后满足条件就交换。
每次回溯到上一层,跟其他的序列进行归并,....直到第一层,跟之前皇帝来签名是一样的,最后的工作交给皇帝来干
归并:给你一格序列,按m=(l+r) 分为两个序列L=[l,m],R=[m,r]; ,然后进行归并
决策如下,
1 ,L[i]<=R[i] A[k]=L[i];
2 , L[i]>R[i] A[k]=R[i];
#include<iostream> #define ss second #define ff first using namespace std; pair<char,int>a[100005],b[100005]; pair<char,int>L[100005],R[100005]; const int INF=1e9+7;void Merge(pair <char,int>a[],int l, int m , int r ) { int n1=m-l; int n2=r-m; for(int i=0;i<n1;i++)L[i]=a[l+i]; for(int i=0;i<n2;i++)R[i]=a[m+i]; L[n1].ss=R[n2].ss=INF; //归并排序的这里很重要 for(int k=l,i=0,j=0;k<r;k++) { if(L[i].ss<=R[j].ss)a[k]=L[i++]; //排序的时候<=一定要加上,不然可能会有不稳定排序的情况发生。 else a[k]=R[j++]; } } int MergeSort(pair<char,int>a[],int l ,int r ) { if(l+1<r) { int m=l+r>>1; MergeSort(a,l,m); MergeSort(a,m,r); Merge(a,l,m,r); } } int main() { int n; cin>>n; for(int i=0;i<n;i++)cin>>a[i].ff>>a[i].ss; MergeSort(a,0,n);for(int i=0;i<n;i++)cout<<a[i].ff<<' '<<a[i].ss<<endl return 0; }
6.选择排序,
核心思想:每次从序列 [i , n]中,选择一格最小的数,跟swap ( a[i] ,a[min])
#include<iostream> using namespace std; int a[105]; int main() { int n; cin>>n; for(int i=0;i<n;i++) { cin>>a[i]; } int ans=0; //选择 for(int i=0;i<n-1;i++) { int Min=i; for(int j=i;j<n;j++) if(a[j]<a[Min]) Min=j; if(Min!=i)swap(a[i],a[Min]); } for(int i=0;i<n;i++)cout<<a[i]<<' '; return 0; }
7 ,计数排序(桶排序)
核心思想:计数,桉数排序,适用于数据的范围小的情况 ai < 1e7
计算每个数字出现的次数,以及统计比该数字小的数字的个数,
1 , C[a[i]] ++;统计个数
2 . C[i] =c[i] + c[ i -1]
3 B[C[ A[i] ] ] =A[i] , C[A [i] ] --;
#include<iostream> #define int long long using namespace std; int A[2000005]; int B[2000005]; int C[10005]; int n,k=10001; int CountSort() { for(int i=0;i<k;i++) C[i]=0; for(int i=1;i<=n;i++)cin>>A[i],C[A[i]]++; for(int i=1;i<=k;i++)C[i]+=C[i-1]; for(int i=n;i>0;i--)B[C[A[i]]]=A[i],C[A[i]]--; cout<<B[1]; for(int i=2;i<=n;i++)cout<<' '<<B[i]; cout<<endl; } signed main() { cin>>n; CountSort(); return 0; }