排序算法汇总

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

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

排序算法汇总

排序算法汇总

排序算法汇总

内部排序算法汇总

排序算法大汇总

常见排序算法汇总