LeetCode 912. 排序数组(快速排序递归和非递归&&堆排序)

给定一个整数数组 nums,将该数组升序排列。

示例 1:

输入:[5,2,3,1]
输出:[1,2,3,5]

示例 2:

输入:[5,1,1,2,0,0]
输出:[0,0,1,1,2,5]

提示:

1 <= A.length <= 10000
-50000 <= A[i] <= 50000

我的思路(快速排序):

这次采用固定一端的快速排序写法,固定最后一个元素,再将它前面的元素,大于它的放后边,小于它的放前面,再将它放入合适放位置,重复若干次。

代码(快排递归版):

class Solution {
public:
    int partition(vector<int>& nums,int i,int j){//排序核心函数,i为左,j为右
        int& k=nums[j];//我采取固定最右端的做法
        while(i<j){
            while(i<j&&nums[i]<=k)i++;//找到左边第一个大于k的值(这里等号一定要加上,可能有重复值),一定要判断i<j,小心越界
            while(i<j&&nums[j]>=k)j--;//找到右边第一个小于k的值
            swap(nums[j],nums[i]);//交换i和j对应位置的值
        }
        swap(k,nums[i]);//把刚刚固定的值放在这个合适的位置上
       return i; //返回这个正确位置
    }
    void QuickSort(vector<int>& nums,int i,int j)//i为左,j为右
    {
        if(i<j){//i如果比j大,显然不合理
            int temp=partition(nums,i,j);//快排中间排序正确的那个值的位置temp
            QuickSort(nums,i,temp-1);//从temp中间划开,分别继续排序左边和右边的值
            QuickSort(nums,temp+1,j);
        }
    }
    vector<int> sortArray(vector<int>& nums) {
        QuickSort(nums,0,nums.size()-1);
        return nums;
    }
};

代码(快排非递归版):(用栈模拟队列,所有的递归转为非递归,都是栈模拟递归调用)

class Solution {
public:
    int partition(vector<int>& nums,int i,int j){//核心排序函数,跟上面一样
        int& k=nums[j];
        while(i<j)
        {
            while(i<j&&nums[i]<=k)++i;
            while(i<j&&nums[j]>=k)--j;
            swap(nums[i],nums[j]);
        }
        swap(nums[i],k);
        return i;
    }
    void QuickSort(vector<int>& nums,int i,int j){
        stack<int> s;//建立一个栈,模拟递归(用不用栈不是必须的,也可以用队列,先排列左边和先排列右边没有区别)
        s.push(i);//先放左(其实先放左还是右无所谓,记住弹出顺序即可)
        s.push(j);//后放右
        while(!s.empty())
        {
            int r=s.top();//这个顺序跟前面那个正好相反,因为是栈,如果是队列就相同
            s.pop();
            int l=s.top();//
            s.pop();
            int temp=partition(nums,l,r);//完成一次的快排,返回正确的位置
            if(l<temp-1){//下面两个判断条件都一样,就是左边序号(下标)不能大于右边
                s.push(l);
                s.push(temp-1);
            }
            if(temp+1<r)
            {
                s.push(temp+1);
                s.push(r);
            }
        }
    }
    vector<int> sortArray(vector<int>& nums) {
        QuickSort(nums,0,nums.size()-1);
        return nums;
    }
};

我的思路(堆排序):

首先构建一个堆(最大堆或者最小堆,根据题目条件来),然后把堆顶元素放入堆底部,之后再把除了堆底部数字的其余数字再进行上述建堆操作。

代码(常规堆排序):

class Solution {
public:
     void partition(vector<int> &nums, int len, int index){//核心建堆函数
         int l=index*2+1;//index的左叶子
         int r=index*2+2;//index的右叶子
         int maxid=index;//这三行用来寻找index以及他的左右叶子中的最大值是谁(位置/下标)
         if(l<len&&nums[l]>nums[maxid])maxid=l;
         if(r<len&&nums[r]>nums[maxid])maxid=r;
         if(maxid!=index)//说明当前最大值不是index
         {
             swap(nums[maxid],nums[index]);//进行相应的交换操作
             partition(nums,len,maxid);//这一步确保maxid(可能是左叶子也可能是右叶子)下面的节点有序(最大堆或者最小堆)
         }
}
 
// 堆排序
    void HeapSort(vector<int> &nums, int size){//其实第二个参数可以不传,第二个参数主要用来控制本次排序的长度大小
        for(int i=size/2-1;i>=0;--i)//size/2-1即找到最后一个非叶子节点,进行建堆操作
        {
            partition(nums,size,i);
        }
        
        for(int i = size - 1; i >= 1; i--){//每一次循环都能把最大(最小)元素放在堆顶
                swap(nums[0], nums[i]);        
                partition(nums, i, 0);//i值每次都在减少,也就是每次排序长度减少,因为最后一个已经是正确位置了,所以不用管了      
            }
        }
    vector<int> sortArray(vector<int>& nums) {
       HeapSort(nums,nums.size());
        return nums;
    }
};

代码(algorithm头文件自带堆排序):

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
       make_heap(nums.begin(),nums.end());//建堆操作
       sort_heap(nums.begin(),nums.end());//堆排序
       return nums;
    }
};

后记:

其实algorithm头文件还有很多地方可以探索,刚刚说的建堆不拘泥于建最小堆,还可以建立最大堆,我们甚至可以自己提供compare函数比较,比如下面,甚至我们自己提供compare函数还可以给结构体建立最大堆和最小堆,具体实现还是看compare函数怎么写了,还有可以提供稳定排序的函数---partial_sort(),同样也可以提供compare函数进行比较。

其实对一个数组排序,不仅仅可以给数字排序,甚至是结构体,我们只需要把排序函数中的大于小于改为一个bool返回值的compare函数即可。活学活用,解决一类问题。

make_heap(nums.begin(),nums.end(),greater<int>());
sort_heap(nums.begin(),nums.end(),greater<int>());

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值