排序算法汇总

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++)
                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);//归并
        
    

以上是关于排序算法汇总的主要内容,如果未能解决你的问题,请参考以下文章

如何在快速排序中选择枢轴值?

C++ 快速排序枢轴优化

数据结构和算法基础之快速排序

快速排序(三种算法实现和非递归实现)

快速中的分割算法的解析与应用

C++ 向量快速排序 - 似乎对不同的枢轴有不同的工作方式