1.选择排序
cpp
void selectsort(vector<int>& v)
{
for(int i=0;i<v.size()-1;i++)
{
int mini=i;
for(int j=i+1;j<v.size();j++)
{
if(v[i]>v[j])
{
mini=j;
}
}
if(mini!=i)
swap(v[i],v[mini]);
}
}
2.堆排序
cpp
void adjustdown(vector<int>& v,int root,int size)
{
int largest=root;
int left=2*root+1;
int right=2*root+2;
if(left<size&&v[left]>v[largest]) largest=left;
if(right<size&&v[right]>v[largest]) largest=right;
if(largest!=root)
{
swap(v[root],v[largest]);
adjustdown(v,largest,size);
}
}
void heapsort(vector<int>& v)
{
int n=v.size();
for(int i=n/2-1;i>=0;i--) 非叶子结点
{
adjustdown(v,i,n);
}
for(int i=n-1;i>0;i--) 大堆只是父结点大于子节点,相邻子节点不一定大于
{
swap(v[i],v[0]);
adjustdown(v,0,n);
}
}
3.插入排序
cpp
void insertsort(vector<int>& v)
{
int n=v.size();
for(int i=1;i<n;i++)
{
int key=v[i];
int j=i-1;
while(j>=0&&v[j]>key)
{
v[j+1]=v[j];
j--;
}
v[j+1]=key;
}
}
4.希尔排序
cpp
void shellsort(vector<int>& v)
{
int n=v.size();
int gap=1;
while(gap<n/3)
{
gap=gap*3+1;
}
for(;gap>0;gap=(gap-1)/3)
{
for(int i=gap;i<n;i++)
{
int key=v[i];
int j=i-gap;
while(j>=0&&v[j]>key)
{
v[j+gap]=v[j];
j-=gap;
}
v[j+gap]=key;
}
}
}
5.冒泡排序
cpp
void bubblesort(vector<int>& arr)
{
for(int i=0;i<arr.size()-1;i++)
{
for(int j=0;j<arr.size()-1-i;j++)
{
if(arr[j]>arr[j+1])
{
swap(arr[j],arr[j+1]);
}
}
}
}
6.快速排序
cpp
//快速排序 hoare法
int findkeyi(vector<int>& arr,int left,int right)
{
int pivot=arr[left];
int i=left-1;
int j=right+1;
while(true)
{
do{i++;}while(arr[i]<pivot);
do{j++;}while(arr[j]>pivot);
if(i>=j) return j;
swap(arr[i],arr[j]);
}
}
void quicksort(vector<int>& arr,int left,int right)
{
if(left<right)
{
int gugu=findkeyi(arr,left,right);
quicksort(arr,left,gugu);
quicksort(arr,gugu+1,right);
}
}
//挖坑法
int findkeyi(vector<int>& arr,int left,int right)
{
int pivot=arr[left];
int hole=left;
while(left<right)
{
while(left<right&&arr[right]>=pivot) right--;
arr[hole]=arr[right];
hole=right;
while(left<right&&arr[left]<=pivot) left++;
arr[hole]=arr[left];
hole=left;
}
arr[hole]=pivot;
return hole;
}
void quicksort(vector<int>& arr,int left,int right)
{
if(left<right)
{
int gugu=findkeyi(arr,left,right);
quicksort(arr,left,gugu-1);
quicksort(arr,gugu+1,right);
}
}
//lomuto
int findkeyigugu(vector<int>& arr,int left,int right)
{
int pivot=arr[right];
int i=left-1;
for(int j=left;j<right;j++)
{
if(arr[j]<pivot)
{
i++;
swap(arr[i],arr[j]);
}
}
swap(arr[i+1],arr[right]);
return i+1;
}
void quicksort(vector<int>& arr,int left,int right)
{
if(left<right)
{
int gugu=findkeyi(arr,left,right);
quicksort(arr,left,gugu-1);
quicksort(arr,gugu+1,right);
}
}
//非递归双指针
void quicksort(vector<int>& arr,int left,int right)
{
stack<pair<int,int>> st;
st.push({left,right});
while(!st.empty())
{
auto [l,r]=st.top();
st.pop();
if(l>=r) continue;
int gugu=findkeyigugu(arr,l,r);
st.push({gugu+1,r});
st.push({l,gugu-1});
}
}
7.归并排序
cpp
void merge(vector<int>& arr,int left,int mid,int right)
{
int n1=mid-left+1;
int n2=right-mid;
vector<int> gu(n1),gugu(n2);
for(int i=0;i<n1;i++)
{
gu[i]=arr[left+i];
}
for(int j=0;j<n2;j++)
{
gugu[j]=arr[mid+1+j];
}
int i=0;
int j=0;
int k=left;
while(i<n1&&j<n2)
{
if(gu[i]<gugu[j])
{
arr[k]=gu[i];
i++;
}
else{
arr[k]=gugu[j];
j++;
}
k++;
}
while(i<n1)
{
arr[k]=gu[i];
i++;
k++;
}
while(j<n2)
{
arr[k]=gugu[j];
k++;
j++;
}
}
void mergesort(vector<int>& arr,int left,int right)
{
if(left<right)
{
int mid=left+(right-left)/2;
mergesort(arr,left,mid);
mergesort(arr,mid+1,right);
merge(arr,left,mid,right);
}
}
8.计数排序
cpp
void countingsort(vector<int>& arr)
{
if(arr.empty()) return;
int min=*min_element(arr.begin(),arr.end());
int max=*max_element(arr.begin(),arr.end());
int l=max-min+1;
vector<int> result(l,0);
for(int num:arr)
{
result[num-min]++; 每个数出现了几次,哈希的思想
}
int index=0;
for(int i=0;i<l;i++)
{
int num=i+min;
while(result[i]>0)
{
arr[index]=num;
result[i]--;
index++;
}
}
}
9.总结
- 选择排序:简单直观,每次选最小元素交换,时间复杂度 O (n²),不稳定。
- 堆排序:利用堆的特性,时间复杂度 O (n log n),空间复杂度 O (1),不稳定。
- 插入排序:适合近乎有序的数据,时间复杂度 O (n²),稳定。
- 希尔排序:插入排序的优化版,通过增量分组减少移动次数,时间复杂度与增量有关,不稳定。
- 冒泡排序:通过相邻元素交换 "浮" 出最大元素,时间复杂度 O (n²),稳定(可优化)。
- 快速排序:分治法的典型应用,平均时间复杂度 O (n log n),最坏 O (n²),不稳定,有多种分区实现(hoare、挖坑、lomuto 等)。
- 归并排序:分治法,时间复杂度 O (n log n),空间复杂度 O (n),稳定。
- 计数排序:非比较排序,适合范围小的整数,时间复杂度 O (n + k),稳定(标准实现)。