排序
平均 | 最好 | 最坏 | 稳定性 | 额外空间 | 类型 |
---|---|---|---|---|---|
O ( n 2 ) O(n^2) O(n2) | O ( n 2 ) O(n^2) O(n2) | O ( n 2 ) O(n^2) O(n2) | 否 | O ( 1 ) O(1) O(1) | 选择 |
O ( n 2 ) O(n^2) O(n2) | O ( n ) O(n) O(n) | O ( n 2 ) O(n^2) O(n2) | 是 | O ( 1 ) O(1) O(1) | 冒泡 |
O ( n 2 ) O(n^2) O(n2) | O ( n ) O(n) O(n) | O ( n 2 ) O(n^2) O(n2) | 是 | O ( 1 ) O(1) O(1) | 插入 |
O ( n log ( n ) ) O(n\log(n)) O(nlog(n)) | O ( n log ( n ) ) O(n\log(n)) O(nlog(n)) | O ( n log ( n ) ) O(n\log(n)) O(nlog(n)) | 否 | O ( 1 ) O(1) O(1) | 堆 |
O ( n log ( n ) ) O(n\log(n)) O(nlog(n)) | O ( n log ( n ) ) O(n\log(n)) O(nlog(n)) | O ( n 2 ) O(n^2) O(n2) | 否 | O ( 1 ) O(1) O(1) | 快速 |
O ( n log ( n ) ) O(n\log(n)) O(nlog(n)) | O ( n log ( n ) ) O(n\log(n)) O(nlog(n)) | O ( n log ( n ) ) O(n\log(n)) O(nlog(n)) | 是 | O ( n ) O(n) O(n) | 归并 |
亚 O ( n log ( n ) ) = O ( n + k ) O(n\log(n))=O(n+k) O(nlog(n))=O(n+k) | O ( n + k ) O(n+k) O(n+k) | O ( n + k ) O(n+k) O(n+k) | 是 | O ( n + k ) O(n+k) O(n+k) | 计数 |
亚 O ( n log ( n ) ) = O ( n + k ) O(n\log(n))=O(n+k) O(nlog(n))=O(n+k) | O ( n 2 ) O(n^2) O(n2) | O ( n ) O(n) O(n) | 是 | O ( n + k ) O(n+k) O(n+k) | 桶 |
O ( n ⋅ k ) O(n \cdot k) O(n⋅k) | O ( n ⋅ k ) O(n \cdot k) O(n⋅k) | O ( n ⋅ k ) O(n \cdot k) O(n⋅k) | 是 | O ( n + k ) O(n + k) O(n+k) | 基数 |
O ( n 1.3 ) O(n^{1.3}) O(n1.3) | O ( n ) O(n) O(n) | O ( n 2 ) O(n^2) O(n2) | 否 | O ( 1 ) O(1) O(1) | 希尔 |
选择、冒泡、插入
选择
vector<int> selectionSort(vector<int>& nums) {
int n = nums.size();
for (int i = 0; i < n; i++){
int min_idx=i;
int min_val = nums[i];
for (int j = i+1; j < n; j++){
if (nums[j]<min_val){
min_idx = j;
min_val=nums[j];
}
}
swap(nums[i], nums[min_idx]); // 导致不稳定
}
return nums;
}
冒泡
vector<int> bubbleSort(vector<int>& nums) {
int n = nums.size();
bool sorted = false; // 终止指示
for (int i = 0; i < n; i++){ // 记录有序元素个数
sorted = true;
for (int j = 0; j < n-i-1; j++){
if (nums[j]>nums[j+1]){
swap(nums[j], nums[j+1]); // 可以使用tmp存储,在合适时插入
sorted = false;
}
}
if (sorted) break;
}
return nums;
}
插入
vector<int> insertionSort(vector<int>& nums) {
int n = nums.size();
for (int i = 1; i < n; i++){
int cur = nums[i];
int j = i-1;
for(; j >= 0; --j){
if (cur < nums[j]){
nums[j+1] = nums[j];
if (j==0) nums[j]=cur;
}else{
nums[j+1] = cur;
break;
}
}
}
return nums;
}
堆、快速、归并
堆
需要构造优先级队列时,额外增加push_heap即可。元素添加到末尾,然后沿着父亲链上滤。
template<typename Iter>
inline void filter_down(Iter first, int total, int cur){
while(true){
auto cur_it = first+cur-1;
int left_idx = total<cur*2?cur:cur*2;
int right_idx = total<cur*2+1?cur:cur*2+1;
auto left_child = first+left_idx-1;
auto right_child = first+right_idx-1;
int cur_val = *(first+cur-1);
if (cur_val>=*left_child && cur_val>=*right_child){break;}
int child_idx = *left_child>*right_child?cur*2:cur*2+1;
auto larger_it = first+child_idx-1;
swap(*larger_it, *cur_it);
cur = child_idx;
}
}
template<typename Iter>
void make_heap_(Iter first, Iter end){
size_t total = distance(first, end);
for(int idx = total; idx>0; idx--){
filter_down(first, total, idx);
}
}
template<typename Iter>
void pop_heap_(Iter first, Iter end){
int total = distance(first, end)-1;
swap(*first, *(end-1));
filter_down(first, total, 1);
}
class Solution {
public:
vector<int> heapSort(vector<int>& nums) {
size_t n = nums.size();
make_heap_(nums.begin(), nums.end());
for (size_t i = 0; i < n; i++){
pop_heap_(nums.begin(), nums.end()-i);
}
return nums;
}
};
快速
原地排序。对于堆排序来说优点在于可并行,使用不同物理核心处理不同部分。缺点是最坏情况的复杂度较高,可能被黑客利用进行拒绝服务攻击。
class Solution {
public:
vector<int> sortArray(vector<int>& nums) {
quickSort(nums, 0, nums.size()-1);
return nums;
}
void quickSort(vector<int>&nums, int lo, int hi){
if (lo>=hi) return;
int divider = partition(nums, lo, hi);
quickSort(nums, lo, divider-1);
quickSort(nums, divider+1, hi);
}
int partition(vector<int>&nums, int lo, int hi){
int pivot_idx = (lo+hi)/2; // 随机化pivot位置
swap(nums[pivot_idx], nums[hi]);
int& pivot = nums[hi];
lo -= 1;
while(lo<hi){
while(++lo<hi&&nums[lo]<pivot){}
while(lo<hi&&pivot<=nums[hi]){
hi--;
}
swap(nums[lo], nums[hi]);
}
swap(nums[lo], pivot);
return lo;
}
};
归并
优点有稳定,可以外排等。
空间未优化,
S
(
n
)
=
O
(
n
log
(
n
)
)
S(n)=O(n\log (n))
S(n)=O(nlog(n))
class Solution {
public:
vector<int> sortArray(vector<int>& nums) {
mergeSort(nums, 0, nums.size());
return nums;
}
void mergeSort(vector<int>& nums, int lo, int hi){
if (hi-lo==1) return;
int mid = (lo+hi)/2;
mergeSort(nums, lo, mid);
mergeSort(nums, mid, hi);
int n = hi-lo, offset=lo, sub_n1 = mid-lo;
vector<int> nums_cp(nums.begin()+lo, nums.begin()+hi);
int i = 0;
mid -= lo; lo = 0;
while(true){
if (lo>=sub_n1 || mid>=n){
break;
}
if (nums_cp[lo]<=nums_cp[mid]){
nums[offset+i++] = nums_cp[lo++];
}else{
nums[offset+i++] = nums_cp[mid++];
}
}
while(lo<sub_n1){
nums[offset+i++] = nums_cp[lo++];
}
while(mid<n){
nums[offset+i++] = nums_cp[mid++];
}
}
};
空间优化, S ( n ) = O ( n ) S(n)=O(n) S(n)=O(n)
class Solution {
public:
vector<int> nums_cp;
vector<int> sortArray(vector<int>& nums) {
nums_cp = vector<int>(nums);
mergeSort(nums, 0, nums.size());
return nums;
}
void mergeSort(vector<int>& nums, int lo, int hi){
if (hi-lo==1) return;
int mid = (lo+hi)/2;
mergeSort(nums, lo, mid);
mergeSort(nums, mid, hi);
int n = hi-lo, offset=lo, sub_n1 = mid-lo;
copy(nums.begin()+lo, nums.begin()+hi, nums_cp.begin());
// vector<int> nums_cp(nums.begin()+lo, nums.begin()+hi);
int i = 0;
mid -= lo; lo = 0;
while(true){
if (lo>=sub_n1 || mid>=n){
break;
}
if (nums_cp[lo]<=nums_cp[mid]){
nums[offset+i++] = nums_cp[lo++];
}else{
nums[offset+i++] = nums_cp[mid++];
}
}
while(lo<sub_n1){
nums[offset+i++] = nums_cp[lo++];
}
while(mid<n){
nums[offset+i++] = nums_cp[mid++];
}
}
};
数组的非递归归并排序
参考这位博主
子串长度每次翻倍,注意边界。
基数
希尔
计数
桶