这篇博客主要梳理了一些排序算法,为了测试算法的正确性,于是选择了力扣上的一道裸题去测试。算法的正确性相对来讲可以保证。
- [LeetCode912. 排序数组]
传送门
插入排序
class Solution {
public:
vector<int> insertion_sort(vector<int>& nums) {
for(int j=1;j<nums.size();j++){
int i = j-1;
int key = nums[j];
while(i>=0 && nums[i]>key){
nums[i+1] = nums[i];
i--;
}
nums[i+1] = key;
}
return nums;
}
};
希尔排序
class Solution {
public:
vector<int> shell_sort(vector<int>& nums) {
int n = nums.size();
for(int gap = n/2;gap>=1;gap/=2){
for(int j=gap;j<nums.size();j++){
int i = j-gap;
int key = nums[j];
while(i>=0 && nums[i]>key){
nums[i+gap] = nums[i];
i -= gap;
}
nums[i+gap] = key;
}
}
return nums;
}
};
归并排序
class Solution {
public:
vector<int> sortArray(vector<int>& nums) {
merge_sort(nums,0,nums.size()-1);
return nums;
}
void merge_sort(vector<int> &nums, int l, int r){
if(l>=r) return;
int mid = l+(r-l)/2;
merge_sort(nums,l,mid);
merge_sort(nums,mid+1,r);
helper_merge(nums,l,r);
}
void helper_merge(vector<int> &nums, int l, int r){
vector<int> temp;
int mid = l+(r-l)/2;
int i = l;
int j = mid+1;
while(i<=mid && j<=r){
if(nums[i]<=nums[j]) temp.push_back(nums[i++]);
else temp.push_back(nums[j++]);
}
while(i<=mid) temp.push_back(nums[i++]);
while(j<=r) temp.push_back(nums[j++]);
for(int i=l;i<=r;i++){
nums[i] = temp[i-l];
}
}
};
快速排序
快排的最核心的地方就是如何根据一个基准值将一个数组分成两部分。
- 《啊哈算法》的版本(双向指针)
class Solution {
public:
vector<int> sortArray(vector<int>& nums) {
if(nums.size()<=1) return nums;
quick_sort(nums,0,nums.size()-1);
return nums;
}
void quick_sort(vector<int> &nums,int l,int r){
if(l>=r) return;
int base = nums[l];
int i = l , j = r;
while(i<j){
while(i<j && nums[j]>=base) j--;
while(i<j && nums[i]<=base) i++;
swap(nums[i],nums[j]);
}
// 基准值归位
// 此时 i==j 并且 nums[i]<base 因为是j指针先移动的
nums[l] = nums[i];
nums[i] = base;
quick_sort(nums,l,i-1);
quick_sort(nums,i+1,r);
}
};
- 《算法导论》的版本(同向指针)
- 循环不变量法
[l,i] 都小于等于x,
[i+1,j] 都大于x,
[j+1,r-1] 尚未处理,
nums[r] 是基准值。
- 循环不变量法
class Solution {
public:
vector<int> sortArray(vector<int>& nums) {
if(nums.size()<=1) return nums;
quick_sort(nums,0,nums.size()-1);
return nums;
}
void quick_sort(vector<int> &nums,int l,int r){
if(l>=r) return;
int p = partion(nums,l,r);
quick_sort(nums,l,p-1);
quick_sort(nums,p+1,r);
}
// 循环不变量 [l,i] 都小于等于x,
// [i+1,j] 都大于x
// [j+1,r-1] 尚未处理
// nums[r] 是基准值
int partion(vector<int> &nums,int l,int r){
int x = nums[r];
int i = l-1;
for(int j=l;j<r;j++){
if(nums[j]<=x){
i++;
// 此时nums[i]大于x,而nums[j]小于等于x
// 一交换 循环不变量保持
swap(nums[j],nums[i]);
}
}
swap(nums[i+1],nums[r]);
return i+1;
}
};
堆排序
class Solution {
int heap[50010], size;
void down(int x){
int least = x;
int l = 2*x;
int r = 2*x+1;
if(l<=size && heap[l]<heap[least]) least = l;
if(r<=size && heap[r]<heap[least]) least = r;
if(least!=x){
swap(heap[x],heap[least]);
down(least);
}
}
// 建堆
void build_heap(const vector<int>& nums){
size = nums.size();
for(int i=0;i<size;i++) heap[i+1] = nums[i];
for(int i=size/2;i>=1;i--){
down(i);
}
}
// 依次取出堆顶,然后调整堆。
void heap_sort(vector<int>& nums){
int pos = 0;
while(size){
nums[pos++] = heap[1];
heap[1] = heap[size--];
down(1);
}
}
public:
vector<int> sortArray(vector<int>& nums) {
build_heap(nums);
heap_sort(nums);
return nums;
}
};
计数排序
力扣的数据: [ − 50000 , 50000 ] [-50000,50000] [−50000,50000],用一个线性函数将所有元素映射到区间 [ 0 , 100000 ] [0,100000] [0,100000]
class Solution {
static const int N = 100010;
int bin[N] = {
0};
public:
vector<int> sortArray(vector<int>& nums) {
vector<int> ans;
for(int x:nums){
bin[f(x)] ++;
}
for(int i=0;i<N;i++){
for(int j=0;j<bin[i];j++){
ans.push_back(g(i));
}
}
return ans;
}
int f(int num){
return num + 50000;
}
int g(int id){
return id - 50000;
}
};
/*
*/
基数排序
class Solution {
void sortByKth(vector<int>& nums,int k) {
vector<int> bin[10];
for(int x:nums){
bin[ f(x,k) ].push_back(x);
}
int pos = 0;
for(int i=0;i<10;i++){
for(int j=0;j<bin[i].size();j++){
nums[pos++] = bin[i][j];
}
}
}
int f(int num,int k){
while(k--){
num /= 10;
}
return num % 10;
}
public:
vector<int> sortArray(vector<int>& nums){
for(int &x:nums) x += 50000;
for(int k=0;k<=5;k++){
sortByKth(nums,k);
}
vector<int> ans;
for(int &x:nums) x -= 50000;
return nums;
}
};