给定一个整数数组 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>());