排序
稳定性:具有相同关键字的记录排序后次序不变。
代码中数组都从0开始
冒泡排序
稳定,序列有序时O(n)
vector<int> BubbleSort(vector<int> v){
bool f=true;
while(f){
f=false;
for(int i=0;i<n-1;i++){
if(v[i]>v[i+1]){
f=true;
swap(v[i],v[i+1]);
}
}
}
return v;
}
插入排序
序列分为两段,每次从后面拿一个元素插入前半段的正确位置。
稳定,数列几乎有序时效率很高。
vector<int> InsertionSort(vector<int> v){
for(int i=1;i<n;i++){
int j=i-1,cur=v[i];
while(j>=0&&cur<v[j]){
v[j+1]=v[j];
j--;
}
v[j+1]=cur;
}
return v;
}
基数排序
按关键字重要性从低到高依次排序
稳定的排序算法,如果共有k个关键字且支持计数排序,那么复杂度为O(kn+关键字值域大小的和)
#define get(x,k) (x%p[i+1]/p[i])
vector<int> RadixSort(vector<int> v, int k=2){
int p[10]={1},cnt[10];
for(int i=1;i<k+1;i++)
p[i]=p[i-1]*10;
vector<int> res(n);
for(int i=0;i<k;i++){
memset(cnt,0,10*sizeof(int));
for(int j=0;j<n;j++){
cnt[get(v[j],i)]++;
}
for(int j=1;j<10;j++)
cnt[j]+=cnt[j-1];
for(int j=n-1;j>=0;j--){
res[--cnt[get(v[j],i)]]=v[j];
}
v=res;
}
return res;
}
快速排序
每次挑选一个元素作pivot,将比它小的放在左侧,比它大的放在右侧;然后对被这个元素分割开的序列递归进行这个操作
partition有多种实现方法。都是不稳定的。
可以用快排的思想线性找第k大,每次挑选出pivot进行partition操作后,可以缩小第k大元素所在区间。
//in-place(原地)方案
int partition1(vector<int>& v,int l,int r){
int pivot=v[l];
while(l<r){
while(l<r&&v[r]>=pivot)
r--;
v[l]=v[r];
while(l<r&&v[l]<=pivot)
l++;
v[r]=v[l];
}
v[l]=pivot;
return l;
}
int partition2(vector<int>& v,int l,int r){
int pivot=v[r],cur=l;
for(int i=l;i<r;i++){
if(v[i]<=pivot){
swap(v[i],v[cur]);
cur++;
}
}
swap(v[r],v[cur]);
return cur;
}
void QuickSort(vector<int>& v,int low,int high){
if(low>=high)
return;
int pivot=partition2(v,low,high);
QuickSort(v,low,pivot-1);
QuickSort(v,pivot+1,high);
}
归并排序
和快排不同的是,先递归,再对已排序的两段序列进行merge操作
归并排序还可以求逆序对,每次merge操作时如果后半段有需要提到前面的,那它之前比它大的就加在结果里。
void MergeSort(vector<int>& v,int l,int r){
if(l>=r)
return;
int mid=(l+r)>>1;
MergeSort(v,l,mid);
MergeSort(v,mid+1,r);
vector<int> tmp(r-l+1);
int p=l,q=mid+1;
for(int i=0;i<=r-l;i++){
if(q>r||(p<=mid&&v[p]<v[q])){
tmp[i]=v[p++];
}else{
tmp[i]=v[q++];
}
}
for(int i=0;i<=r-l;i++){
v[i+l]=tmp[i];
}
}
堆排序
先在数组上建立最大堆,然后不断把top元素和堆最后的元素swap,并维护size-1的堆
不稳定
max_heapify(最大堆化):把top元素不断地和比它大的子节点交换,当堆仅发生了pop操作而改变时,执行一次max_heapify即可将堆恢复性质。即堆操作中的向下调整
void max_heapify(vector<int>& v,int st,int ed){
int fa=st,son=fa*2+1;
while(son<=ed){
if(son+1<=ed&&v[son+1]>v[son])
son++;
if(v[fa]>=v[son])
return;
else{
swap(v[son],v[fa]);
fa=son;
son=son*2+1;
}
}
}
void HeapSort(vector<int>& v,int len=n){
for(int i=len/2-1;i>=0;i--){
//len/2-1是len-1位置节点的父亲
max_heapify(v,i,len-1);
}
for(int i=len-1;i>0;i--){
swap(v[0],v[i]);
max_heapify(v,0,i-1);
}
}