• 排序问题


    1.堆排序

    要求:对于大顶堆,孩子节点的值小于父节点。

    说明:数据会存储在数组中,从数组下标1开始存储根节点,假如i为父节点,则2*i是左孩子,2*i+1是右孩子。

    方法:向上调整

    步骤:

    第一步:建堆,从有孩子节点p开始调整,将p的两个孩子节点较大者与父节点(p)交换,再调整交换过的以子节点为根的树,直到以p为根节点的树满足要求。

    第二步:调整堆,因为根节点是最大的,保存后;将最后一个节点与根节点交换,调整树,直到满足要求。调用建堆的方法即可。

    #include "iostream"
    #include "vector"
    using namespace std;
    //大顶堆的构造,传入的p是父节点,使得以p为根节点的树,满足大顶堆
    void HeapAdjust(vector<int> &vec,int p,int n){
        int temp=vec[p];
        for (int i = 2 * p; i <= n;i*=2)  {
            if (i < n&&vec[i] < vec[i + 1])
                i++;//找到两个孩子结点中最大的
            if (temp >= vec[i])
                break;//根节点大于子节点,则退出
            vec[p] = vec[i];    //将孩子节点放到父节点上
            p = i;
        }
        vec[p] = temp;//将开始的p节点放到最终位置
    }
    
    //大顶堆排序,调整堆
    void HeapSort(vector<int> &vec){
        int n=vec.size()-1;
        //首先将无序数列转换为大顶堆
        for (int i = n / 2; i > 0;i--)    //注意由于是完全二叉树,所以我们从一半向前构造,传入父节点
            HeapAdjust(vec, i, n);
        
        //将最大的元素放入目标位置,然后将剩余元素重新构造大顶堆
        for (int i = n; i >1;i--){
            swap(vec[1], vec[i]);
            HeapAdjust(vec, 1, i - 1);
        }
    }
    int main(){
        //注意数组中第一个值是不参与排序的,无意义的
        vector<int> vec={0,23,4,1,2,5,45,3,345,55};
        HeapSort(vec);
        //1 2 3 4 5 23 45 55 345
        for (auto item:vec)cout<<item<<" ";
        return 0;
    }

    2.快排

    快排有两个步骤:

    第一步:选取数组的第一个数值为枢轴值,而后将数组调整为左边小于枢轴值,右边大于枢轴值。

    第二步:分别对枢轴值左边和右边部分执行上述操作。

    具体示例如下:

    假如有如下数组

     一趟排序之后

    而后分别对枢轴值左边部分和右边部分做同样的操作,最终得到有序数组。

    对应的程序代码如下:

    #include "iostream"
    #include "vector"
    using namespace std;
    //一趟排序的第一种写法
    int ajust_one(vector<int> &vec,int left,int right){
        int pivot=vec[left];
        //跳出循环是left=right
        while (left<right){
            //如下顺序不可调换
            while (left<right&&vec[right]>=pivot)right--;
            vec[left]=vec[right];
            while (left<right&&vec[left]<=pivot)left++;
            vec[right]=vec[left];
    
        }
        //将枢轴值放到归位
        vec[left]=pivot;
        return left;
    }
    //一趟排序的第二种写法
    int ajust_two(vector<int> &vec,int left,int right){
        int left_start=left;
        int pivot=vec[left];
        //跳出循环是left=right
        while (left<right){
            //如下顺序不可调换
            while (left<right&&vec[right]>=pivot)right--;
            while (left<right&&vec[left]<=pivot)left++;
            swap(vec[left],vec[right]);//交换两个值
        }
        //将枢轴值放到归位
        vec[left_start]=vec[left];
        vec[left]=pivot;
        return left;
    }
    void quickSort(vector<int> &vec,int left,int right){
        if(left<right){
            int mid=ajust_one(vec,left,right);
            quickSort(vec,left,mid-1);
            quickSort(vec,mid+1,right);
        }
    }
    int main(){
        vector<int> vec={23,4,1,2,5,45,3,345,55};
        quickSort(vec,0,vec.size()-1);
        //1 2 3 4 5 23 45 55 345
        for (auto item:vec)cout<<item<<" ";
        return 0;
    }

    3.归并排序

    经典的分治策略,先分成小问题,而后再合并,最后问题得到求解。

    #include "iostream"
    #include "vector"
    using namespace std;
    void ajust(vector<int> &vec,int left,int mid,int right){
        vector<int> temp(right-left+1,0);
        int left_start=left;//保存开始位置
        int mid_right=mid+1;//
        int i=0;
        while (left<=mid&&mid_right<=right){
            if(vec[left]<vec[mid_right])
                temp[i++]=vec[left++];
            else
                temp[i++]=vec[mid_right++];
        }
        //将未完成的部分,补到数组后面
        while(left<=mid)temp[i++]=vec[left++];
        while(mid_right<=right) temp[i++]=vec[mid_right++];
        //将临时数组的值拷贝到原数组中
        i=0;
        while(left_start<=right)vec[left_start++]=temp[i++];
    }
    void merge(vector<int> &vec,int left,int right){
        if(left<right){
            int mid=(left+right)/2;
            merge(vec,left,mid);//left到mid是有序,包括边界
            merge(vec,mid+1,right);//mid+1到right有序,包括边界
            ajust(vec,left,mid,right);
        }
    }
    int main(){
        vector<int> vec={23,4,1,2,5,45,3,345,55};
        merge(vec,0,vec.size()-1);
        //1 2 3 4 5 23 45 55 345
        for (auto item:vec)cout<<item<<" ";
        return 0;
    }

    堆排序图解可参考:https://www.cnblogs.com/chengxiao/p/6129630.html

    归并排序详解可参考:https://www.cnblogs.com/chengxiao/p/6194356.html

  • 相关阅读:
    centos 添加 composer
    laravel5 缓存的使用
    git 的使用
    php 消息队列 rabbitmq 的安装使用
    vue插件大汇总
    vue 2.0 Gzip打包压缩
    Easy Mock 为啥那么打不开了?
    element ui 打印 表格
    解决 element 日期范围选择问题(只能选择相邻的 连两个月)
    vue router 的路由传参 params 和 query 的 区别
  • 原文地址:https://www.cnblogs.com/AntonioSu/p/11881597.html
Copyright © 2020-2023  润新知