一.基本介绍
一个算法在n规模下所消耗的时间消耗从大到小如下:
O(1) < O(log n) < O(n) < O(n log n) < O(n ^ 2) < O(n ^ 3)指数级的增长是非常快的.
二.常见的排序算法
根据时间复杂度的不同,常见的算法可以分为3大类。
1.O(n²) 的排序算法
- 冒泡排序
- 选择排序
- 插入排序
2.O(n log n) 的排序算法
- 希尔排序
- 归并排序
- 快速排序
- 堆排序
3.线性的排序算法
- 计数排序
- 桶排序
- 基数排序
各种排序的具体信息
三.各排序算法
冒泡排序 O(N^2)
// 冒泡排序 O(N^2)
void BubbleSort(vector<int>& Arr){
if(Arr.size() < 2)
return;
for (int end = Arr.size() - 1; end > 0; end--){
for (int start = 0; start < end; start++){
if(Arr[start] > Arr[start+1])
swap(Arr[start], Arr[start + 1]);
}
}
}
选择排序 O(N^2)
// 选择排序 O(N^2)
void SelectSort(vector<int>& Arr){
if(Arr.size() < 2)
return;
for (int end = Arr.size() - 1; end > 0; end--){
int maxidx = 0;
for (int start = 0; start < end; start++){
maxidx = Arr[start] > Arr[start + 1] ? start : start + 1;
}
swap(Arr[end], Arr[maxidx]);
}
}
插入排序 O(logN)
// 插入排序 O(logN)
void InsertSort(vector<int>& Arr){
if(Arr.size() < 2)
return;
for (int curidx = 1; curidx < Arr.size(); ++curidx){
for (int preidx = curidx; preidx > 0 && Arr[preidx] < Arr[preidx - 1]; --preidx){
swap(Arr[preidx], Arr[preidx - 1]);
}
}
}
归并排序 O(NlogN)
// 归并排序 O(NlogN)
void MergeSort(vector<int>& Arr){
if(Arr.size() < 2)
return;
mergeCall(Arr, 0, Arr.size() - 1);
}
void mergeAll(vector<int>& Arr, int left, int mid, int right){
vector<int> helper;
int p1 = left, p2 = mid + 1;
while(p1 <= mid && p2 <= right){
helper.emplace_back();
auto &back = helper.back();
back = Arr[p1] < Arr[p2] ? Arr[p1++] : Arr[p2++];
}
while(p1 <= mid){
helper.emplace_back(Arr[p1++]);
}
while(p2 <= right){
helper.emplace_back(Arr[p2++]);
}
for (int i = 0; i < helper.size(); i++){
Arr[left + i] = helper[i];
}
}
void mergeCall(vector<int>& Arr, int left, int right){
if(left == right)
return;
int mid = (right + left >> 1);
mergeCall(Arr, left, mid);
mergeCall(Arr, mid + 1, right);
mergeAll(Arr, left, mid, right);
}
快速排序 O(NlogN)
// 快速排序 O(NlogN)
void QuickSort(vector<int>& Arr){
if(Arr.size() < 2)
return;
QuickSort(Arr, 0, Arr.size() - 1);
}
vector<int> QuickPartition(vector<int>& Arr, int left, int right){
int small = left - 1;
int big = right + 1;
int tocmp = Arr[right];
int curidx = left;
while(curidx < big){
if(Arr[curidx] < tocmp){
swap(Arr[curidx++], Arr[++small]);
}
else if(Arr[curidx] > tocmp){
swap(Arr[curidx], Arr[--big]);
}
else{
curidx++;
}
}
return vector<int>{small + 1, big - 1};
}
void QuickSortCall(vector<int>& Arr, int left, int right){
if(left < right){
int tochange = left + rand() % (right - left + 1);
swap(Arr[right], Arr[tochange]);
vector<int> location = QuickPartition(Arr, left, right);
QuickSortCall(Arr, left, location[0] - 1);
QuickSortCall(Arr, location[1] + 1, right);
}
}
堆排序 O(NlogN)
// 堆排序 O(NlogN)
void HeapSort(vector<int>& Arr){
if(Arr.size() < 1)
return ;
for (int i = 0; i < Arr.size(); i++){
heapinsert(Arr, i);
}
int heapsize = Arr.size();
swap(Arr[0], Arr[--heapsize]);
while(heapsize > 0){
heapify(Arr, 0, heapsize);
swap(Arr[0], Arr[--heapsize]);
}
}
void heapinsert(vector<int>& Arr, int idx){
while(Arr[idx] > Arr[(idx - 1)/2]){
swap(Arr[idx], Arr[(idx - 1) / 2]);
idx = (idx - 1) / 2;
}
}
void heapify(vector<int>& Arr, int idx, int heapsize){
int left = idx * 2 + 1;
while(left < heapsize){
int largest = left + 1 < heapsize && Arr[left + 1] > Arr[left] ? left + 1 : left;
largest = Arr[idx] > Arr[largest] ? idx : largest;
if(largest == idx)
break;
swap(Arr[largest], Arr[idx]);
idx = largest;
left = idx * 2 + 1;
}
}