AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

排序模板大全

作者: 作者的头像   炼心 ,  2019-11-04 00:00:32 ,  所有人可见 ,  阅读 1685


5


8

各种排序

各个排序的空间,时间复杂度,以及稳定性如下

排序方法 时间复杂度(平均) 时间复杂度(最坏) 时间复杂度(最好) 空间复杂度 稳定性 复杂性
直接插入排序 O(n^2) O(n^2) O(n) O(1) 稳定 简单
希尔排序 O(nlog_2n) O(n^2) O(n) O(1) 不稳定 较复杂
直接选择排序 O(n^2) O(n^2) O(n^2) O(1) 不稳定 简单
堆排序 O(nlog_2n) O(nlog_2n) O(nlog_2n) O(1) 不稳定 较复杂
冒泡排序 O(n^2) O(n^2) O(n) O(1) 稳定 简单
快速排序 O(nlog_2n) O(n^2) O(nlog_2n) O(nlog_2n) 不稳定 较复杂
归并排序 O(nlog_2n) O(nlog_2n) O(nlog_2n) O(n) 稳定 较复杂

快速排序

快排的设计思想

快排.png

设计代码

递归版

    void Quick_Sort(int *arr,int l,int r){
        if(l>=r)return;
        int val=arr[l];
        int i=l-1,j=r+1;
        while(i<j){
            do i++; while(val>arr[i]);
            do j--; while(val<arr[j]);
            if(i<j) swap(arr[i],arr[j]);
        }
        //左半部分开始遍历
        Quick_Sort(arr,l,j);
        //右半部分开始遍历
        Quick_Sort(arr,j+1,r);
    }

非递归版的

    void Quick_Sort(int *arr,int l,int r){
        //先存大再存小,取得时候就可以先取小再取大,大小是指的是数组的索引值
        stack<int> lowHight;
        lowHight.push(r);
        lowHight.push(l);
        while(!lowHight.empty()){
            int i=lowHight.top();
            lowHight.pop();
            int j=lowHight.top();
            lowHight.pop();
            if(i>=j)continue;
            int val=a[l];
            while(i<j){
                while(i<j&&val<arr[j])
                    j--;
                swap(arr[j],arr[i]);
                while(i<j&&val>arr[i])
                    i++;
                swap(arr[i],arr[j]);
            }
            //栈的先进后出特性,先处理左边的数据
            //右边
            lowHight.push(r);
            lowHight.push(i+1);
            //左边
            lowHight.push(i-1);
            lowHight.push(l);
        }
    }

梳排序

梳排序是冒泡排序的一种改进方式,为此先把冒泡排序写上来,两者互相对比

冒泡排序

    void Buddle_Sort(int *arr,int l,int r){
        if(l>=r)return;
        for(int i=l;i<r;i++){
            for(int j=i;j<r-i;j++){
                if(arr[j]>arr[j+1])
                    swap(arr[j],arr[j+1]);
            }
        }
    }

梳排序
原理:通过将数组分为小的数组,来达到降低时间复杂度的目的

交换案例
假设待数组[8 4 3 7 6 5 2 1]

待排数组长度为8,而8÷1.3=6,则比较8和2,4和1,并做交换

[8 4 3 7 6 5 2 1]

[8 4 3 7 6 5 2 1]

交换后的结果为

[2 1 3 7 6 5 8 4]

第二次循环,更新间距为6÷1.3=4,比较2和6,1和5,3和8,7和4

[2 1 3 7 6 5 8 4]

[2 1 3 7 6 5 8 4]

[2 1 3 7 6 5 8 4]

[2 1 3 7 6 5 8 4]

只有7和4需要交换,交换后的结果为

[2 1 3 4 6 5 8 7]

第三次循环,更新距离为3,没有交换

第四次循环,更新距离为2,没有交换

第五次循环,更新距离为1,三处交换

[2 1 3 4 6 5 8 7]

[2 1 3 4 6 5 8 7]

[2 1 3 4 6 5 8 7]

三处交换后的结果为[1 2 3 4 5 6 7 8]

交换后排序结束,顺序输出即可得到[1 2 3 4 5 6 7 8]

    void Comb_Sort(int *arr,int l,int r){
       float factor=1.3;
       int g=r-l;
       //n the size of array
       int n=r-l;
       bool flag=true;
       while(g>1||flag){
            g=(g>1)?g/factor:g;
            flag=false;
            int i=0;
            //如果全都排序好了,flag为false,g=1直接跳出循环。
            while(i+g<n){
                if(arr[i]>arr[g+i]){
                    std::swap(arr[i],arr[g+i]);
                    flag=true;
                }
                i=i+1;
            }
       }
    }

归并排序

分而治之

分而治之.png

合并有序子序列

    void merge(vector<int> nums,int l,int r){
        if(l>=r)return;
        int mid=l+r>>1;
        merge(nums,l,mid);
        merge(nums,mid+1,r);
        vector<int> tem;
        int i=l,j=mid+1;
        while(i<=mid&&j<=r){
            if(nums[i]<=nums[j])tem.push_back(nums[i++]);
            else tem.push_back(nums[j++]);
        }
        while(i<=mid)tem.push_back(nums[i++]);
        while(j<=r)tem.push_back(nums[j++]);
        i=l;
        for(auto t:tem){
            nums[i++]=t;
        }
    }

堆排序

    void adjust_heap(vector<int>& nums,int x,int n){
        int l=x*2+1;
        int r=x*2+2;
        int max=x;
        if(l<n&&nums[l]>nums[max])max=l;
        if(r<n&&nums[r]>nums[max])max=r;
        if(max!=x){
            swap(nums[max],nums[x]);
            adjust_heap(nums,max,n);
        }
    }
    void heap_sort(vector<int>& nums){
        int n=nums.size();
        for(int i=n/2-1;i>=0;i--){
            adjust_heap(nums,i,n);
        }
        for(int i=n-1;i>=0;i--){
            swap(nums[i],nums[0]);
            adjust_heap(nums,0,i);
        }
    }

插入排序

直接插入排序

时间复杂度:O(n^2)
具体过程可以参考此图片
直接插入排序

    void DistrictInsertSort(int A[],int n){
            int i,j;
            for(i=1;i<n;i++){
                if(A[i]<A[i-1]){
                    int temp=A[i];
                    for(j=i-1;j>=0&&temp<A[j];--j){
                        A[j+1]=A[j];
                    }
                    A[j+1]=temp;
                }
            }
        }

希尔排序

希尔交换排序

    void ShellSort(int A[],int n){
        //前后记录位置的增量 dk
        //增量dk 并逐步减小增量
        for(int dk=n/2;dk>0;dk/=2){
            //从第dk个元素,逐个对其所在组进行直接插入排序操作
            for(int i=dk;i<n;++i){
                int j=i;
                while(j-dk>=0&&A[j]<A[j-dk]){
                    //插入排序交换法
                    swap(A[j],A[j-dk]);
                    j-=dk;
                }
            }
        }
    }

希尔插入(移动)排序

    void ShellSort(int *A,int n){
        for(int dk=n/2;dk>0;dk/=2){
            for(int i=dk;i<n;i++){
                int j=i;
                int temp=A[i];
                if(A[j]<A[j-dk]){
                    while(j-dk>=0&&temp<A[j-dk]){
                        //移动法
                        A[j]=A[j-dk];
                        j-=dk;
                    }
                    A[j]=temp;
                }
            }
        }
    }

折半插入排序

直接插入排序的改进版,时间复杂度为O(n^2)

    void InsertSort(int A[],int n){
        int i,j=0;
        for(i=1;i<n;i++){
            int temp=A[i];
            low=1;
            high=i-1;
            while(low<high){
                mid=(low+high)/2;
                if(A[mid]>temp){
                    high=mid-1;//查找左半子树
                }
                else
                    low=mid+1;
                for(j=i-1;j>high+1;--j){
                    A[j+1]=A[j];
                }
                A[high+1]=temp;
            }
        }

    }

5 评论


用户头像
烟花易冷   2020-07-21 15:21         踩      回复

折半插入for循环应该在while循环之外吧


用户头像
烟花易冷   2020-07-20 18:17         踩      回复

梳子函数内部改成n=r+1好像就正常了。


用户头像
懒洋洋   2020-06-22 23:30         踩      回复

合并排序的vector[HTML_REMOVED]nums 参数应该是引用。梳子排序无法使用,谢谢


用户头像
秦淮岸灯火阑珊   2019-11-07 21:34         踩      回复

棒棒哒!


用户头像
炼心   2019-11-04 21:35         踩      回复

哪里有不对的请多多指正


App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息