排序算法汇总
Posted Blocking The Sky
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序算法汇总相关的知识,希望对你有一定的参考价值。
一、插入排序
1、直接插入排序
时间复杂度:O(n^2),稳定
代码:
void direct_insert_sort(vector<int>& nums){
int i,j;
for(i=1;i<nums.size();i++){
int temp=nums[i];
for(j=i-1;j>=0&&nums[j]>temp;j--){//将前面比他大的元素后移一位
nums[j+1]=nums[j];
}
nums[j+1]=temp;//填充到正确的位置
}
}
2、折半插入排序
时间复杂度:O(n^2),稳定
代码:
void binary_insert_sort(vector<int>& nums){
int i,j,low,high,mid,temp;
for(i=1;i<nums.size();i++){
temp=nums[i];//nums[i]暂存到temp
low=0;
high=i-1;//设置折半查找的范围
while(low<=high){//折半查找(前面i-1个有序)
mid=(low+high)/2;
if(nums[mid]>temp){
high=mid-1;//查找左半部分
}
else{
low=mid+1;//注意:nums[mid]=temp时,也要low=mid+1,为了保持算法的稳定性
}
}
//结束之后low=high+1,故这里high+1也可以替换为low
for(j=i-1;j>=high+1;j--){
nums[j+1]=nums[j];//统一后移一个位置
}
nums[high+1]=temp;//插入操作
}
}
3、希尔排序
时间复杂度:最坏情况下O(n^ 2),n在某个范围内约为O(n^1.3),不稳定
代码
void shell_sort(vector<int>& nums){
int i,j,dk,temp;
for(dk=nums.size()/2;dk>=1;dk=dk/2){//步长变化,每次选取步长为dk
for(i=dk;i<nums.size();i+=dk){
temp=nums[i];//暂存在temp中
for(j=i-dk;j>=0&&nums[j]>temp;j-=dk){
nums[j+dk]=nums[j];//记录后移
}
nums[j+dk]=temp;//插入
}
}
}
二、交换排序
1、冒泡排序
时间复杂度:O(n^2),稳定
代码
void bubble_sort(vector<int>& nums){
int n=nums.size();
for(int i=0;i<n-1;i++){//n-1趟冒泡
bool flag=false;//表示本趟循环是否发生交换的标志
for(int j=n-1;j>i;j--){//从后往前冒泡
if(nums[j-1]>nums[j]){
swap(nums[j-1],nums[j]);//交换
flag=true;
}
}
if(!flag){
return ;//若本趟没有发生交换说明已经是有序的直接返回即可
}
}
}
2、快速排序
时间复杂度:O(nlogn),最坏情况下O(n^2),不稳定
代码
int partion(vector<int>& nums,int low ,int high){//一趟划分
int pivot=nums[low];//以第一个元素作为枢轴
while(low<high){
while(low<high&&nums[high]>=pivot){
high--;
}
nums[low]=nums[high];//比枢轴小的元素移动到最左端
while(low<high&&nums[low]<=pivot){
low++;
}
nums[high]=nums[low];//比枢轴大的元素移动到最右端
}
nums[low]=pivot;//枢轴存放到最终确定的位置
return low;//返回枢轴的最终位置
}
void quick_sort(vector<int>& nums,int low,int high){
if(low<high){
int pivotpos=partion(nums,low,high);
quick_sort(nums,low,pivotpos-1);
quick_sort(nums,pivotpos+1,high);
}
}
3、随机化优化后的快速排序
代码
int partion(vector<int>& nums,int low ,int high){//一趟划分
int r=rand()%(high-low+1)+low;
int pivot=nums[r];//随机选取一个元素作为枢轴
swap(nums[r],nums[low]);
while(low<high){
while(low<high&&nums[high]>=pivot){
high--;
}
nums[low]=nums[high];//比枢轴小的元素移动到最左端
while(low<high&&nums[low]<=pivot){
low++;
}
nums[high]=nums[low];//比枢轴大的元素移动到最右端
}
nums[low]=pivot;//枢轴存放到最终确定的位置
return low;//返回枢轴的最终位置
}
三、选择排序
1、简单选择排序
时间复杂度:O(n^2),不稳定
代码
void select_sort(vector<int>& nums){
int i,j,min,n;
n=nums.size();
for(i=0;i<n-1;i++){//n-1趟
min=i;//记录最小元素的位置
for(j=i+1;j<n;j++){
if(nums[j]<nums[min]){
min=j;//更新最小元素的位置
}
}
if(min!=i){
swap(nums[i],nums[min]);
}
}
}
2、堆排序
时间复杂度:O(nlogn),不稳定
void build_max_heap(vector<int>& nums,int len){//建立大根堆
for(int i=len/2;i>0;i--){//从len/2-1反复调整堆
head_adjust(i,nums,len);
}
}
void head_adjust(int k,vector<int>& nums,int len){//将以k为根的子树进行调整
nums[0]=nums[k];//暂存子树的根结点
for(int i=k*2;i<=len;i*=2){//沿值较大的子节点向下筛选
if(i<len&&nums[i]<nums[i+1]){
i++;//取值大的子节点的下标
}
if(nums[0]>=nums[i]){
break;//筛选结束
}
else{
nums[k]=nums[i];//调整nums[i]到其双亲结点上
k=i;//修改k值,以便继续向下筛选
}
}
nums[k]=nums[0];//被筛选结点的值放入最终位置
}
void heap_sort(vector<int>& nums,int len){
build_max_heap(nums,len);//初试建堆
for(int i=len;i>1;i--){//n-1趟的交换和建堆过程
swap(nums[i],nums[1]);//堆顶元素和堆底元素交换
head_adjust(1,nums,i-1);//调整,把剩下i-1个元素整理成堆
}
}
四、归并排序
时间复杂度:O(nlogn),稳定
void merge(vector<int>& nums,int low,int mid,int high){//两个有序的分段合并为一个有序的
int B[nums.size()+1];
memset(B,0,sizeof(B));
for(int i=low;i<=high;i++){
B[i]=nums[i];//将nums中的元素全部复制到B中
}
int i,j,k;
for(i=low,j=mid+1,k=i;i<=mid&&j<=high;k++){
if(B[i]<=B[j]){//比较B的左右两段中的元素,同时'='保证算法稳定性
nums[k]=B[i++];
}
else{
nums[k]=B[j++];
}
}
while(i<=mid){//如果第一个表未检测完,复制
nums[k++]=B[i++];
}
while(j<=high){//如果第二个表未检测完,复制
nums[k++]=B[j++];
}
}
void merge_sort(vector<int>& nums,int low,int high){
if(low<high){
int mid=(low+high)/2;//划分为两个子序列
merge_sort(nums,low,mid);//对左侧子序列进行递归排序
merge_sort(nums,mid+1,high);//对右侧子序列进行递归排序
merge(nums,low,mid,high);//归并
}
}
以上是关于排序算法汇总的主要内容,如果未能解决你的问题,请参考以下文章