// 1、冒泡 稳定 O(n^2) [ O(n), O(n^2) ]
#include <vector>
using namespace std;
void bubbleSort(vector<int>& nums){
int n = nums.size();
for(int i = 0; i < n - 1; ++i){
for(int j = 0; j < n - 1 - i; ++j){
if(nums[j] > nums[j + 1]){
swap(nums[j], nums[j + 1]);
}
}
}
}
// 2、选择排序 不稳定,因为交换一次,其他元素的相对位置就变了 O(n^2) [ O(n^2), O(n^2) ]
#include <vector>
using namespace std;
void selectSort(vector<int>& nums){
int n = nums.size();
for(int i = 0; i < n - 1; ++i){
int idx = i;
for(int j = i + 1; j < n; j++){
if(nums[j] < nums[idx]) idx = j;
}
if(idx != i) swap[nums[i], nums[idx]];
}
}
// 3、插入排序 稳定 O(n^2) [ O(n), O(n^2) ]
#include <vector>
using namespace std;
void insertSort(vector<int>& nums){
int n = nums.size();
for(int i = 0; i < n - 1; ++i){
int pre = i;
while(pre >= 0 && nums[pre + 1] < nums[pre]){
swap(nums[pre + 1], nums[pre]);
pre--;
}
}
}
// 4、希尔排序 O(n^1.3) [ O(n), O(n^2) ]
#include <vector>
using namespace std;
void shellSort(vector<int>& nums){
int n = nums.size();
for(int incr = n / 2; incr > 0; incr = incr / 2){
for(int j = incr; j < n; ++j){
int pre = j - incr;
while(pre >= 0 && nums[pre + incr] < nums[pre]){
swap(nums[pre + incr], nums[pre]);
pre -= incr;
}
}
}
}
// 5、归并排序 稳定 O(nlogn) [ O(nlogn), O(nlogn) ]
#include <vector>
using namespace std;
vector<int> temp;
void merge(vector<int>& arr, int l, int mid, int r){
int i = l, j = mid + 1;
int k = 0;
while(i <= mid && j <= r){
if(arr[i] <= arr[j]) temp[k++] = arr[i++];
else temp[k++] = arr[j++];
}
while(i <= mid) temp[k++] = arr[i++];
while(j <= r) temp[k++] = arr[j++];
for(int i = l, j = 0; i <= r; i++, j++){
arr[i] = temp[k];
}
}
void mergeSort(vector<int>& arr, int left, int right){
if(left < right){
int mid = (left + right) >> 1;
mergeSort(arr, temp, left, mid);
mergeSort(arr, temp, mid + 1, right);
merge(arr, temp, mid, right);
}
}
//6、快速排序 不稳定 O(nlogn) [ O(nlogn), O(n^2) ]
// 通过一趟排序将待排记录分隔成独立的两部分,
// 其中一部分记录的关键字均比另一部分的关键字小,
// 则可分别对这两部分记录继续进行排序,以达到整个序列有序。
#include <vector>
using namespace std;
void quickSort(vector<int>& nums, int l, int r){
if(l >= r) return;
int i = l, j = r;
int base = nums[l];
while(i < j){
while(nums[j] >= base && i < j){
j--;
}
while(nums[i] <= base && i < j){
i++;
}
if(i < j){
swap(a[i], a[j]);
}
}
a[left] = a[i];
a[i] = base;
quickSort(nums, left, i - 1);
quickSort(nums, i + 1, right);
}
// 7、堆排序 不稳定 O(nlogn) [ O(nlogn), O(nlogn) ]
#include <vector>
using namespace std;
//-----堆排序:根据数组下标和节点的对应关系:father = son * 2 + 1 和 son * 2 + 2;
void HeapSort(vector<int>& arr) {
int n = arr.size() - 1; // n为最后一个下标
//(1)初始化大顶堆:从最后一个父节点开始进行调整
for (int i = n / 2; i >= 0; i--) {
heapify(arr, i, n);
}
//(2)堆排序:交换堆顶元素和当前最后第一个元素
for (int i = n; i > 0; i--) {
swap(arr[0], arr[i]);
n -= 1;
heapify(arr, 0, n);
}
}
// 递归
void heapify(vector<int>& arr, int start, int end) {
if (start >= end) return;
int father = start, son = father * 2 + 1;
if (son > end) return; //左不存在
if (son + 1 <= end && arr[son] < arr[son + 1]) son++; //左右都存在需要比较
if (son <= father) return; //如果父节点大于孩子,直接返回
else swap(arr[son], arr[father]); //交换之后继续向下判断
heapify(arr, son, end);
}
// 8、计数排序 稳定 O(n + k) [ O(n + k), O(n + k) ]
#include <vector>
using namespace std;
void countSort(vector<int>& arr){
int amax = *max_element(arr.begin(), arr.end());
//统计元素出现的次数
vector<int> countarr((amax+1), 0); //拓展:考虑不从0开始如何计数
for(auto a : arr){
countarr[a]++;
}
//重新构建arr
arr.clear();
for(int i = 0; i < amax + 1; i++){
while((i < amax + 1) && countarr[i] != 0){
arr.push_back(i);
countarr[i]--;
}
}
}
//以上方法不稳定,如何调整-->使用累加数组
void countSort1(vector<int>& arr) {
int n = arr.size();
int max = *max_element(arr.begin(), arr.end());
vector<int> count(max + 1, 0); //从0开始需要max+1个位置
for (auto x : arr) count[x]++; //统计出现次数
//保证稳定性,使用累加数组
for (int i = 1; i < count.size(); i++) count[i] += count[i - 1];
//根据累加数组 反向重建数组
vector<int> temp(n);
for (int i = n - 1; i >= 0; i--) {
//找到arr[i]在哪一个位置,根据count就可以知道存放的位置。用前先--,对应存放位置
temp[--count[arr[i]]] = arr[i];
}
arr.assign(temp.begin(), temp.end());
}
// 9、桶排序 稳定 O(n + k) [ O(n), O(n^2) ]
// 桶排序是计数排序的升级版
#include <vector>
using namespace std;
void bucketSort(vector<int>& arr) {
//初始化桶,桶的个数及开辟空间
int aminid = 0, amaxid = 0;
int n = arr.size();
for (int i = 1; i < n; i++) {
if (arr[i] > arr[amaxid]) amaxid = i;
if (arr[i] < arr[aminid]) aminid = i;
}
int amax = arr[amaxid], amin = arr[aminid];
int count = (amax - amin) / n + 1;
vector<vector<int>> bucket(count, vector<int>());
//将元素映射到每个桶中,利用均匀分布的思想进行映射
for (int i = 0; i < n; i++) {
int k = (arr[i]-amin)/ n;//映射到 需要放在哪一个桶
bucket[k].push_back(arr[i]);//放入桶中
}
arr.clear();
//对每个桶进行排序(插入排序),然后拼接
for (int i = 0; i < count; i++) {
insertSort(bucket[i]);
arr.insert(arr.end(),bucket[i].begin(),bucket[i].end());
}
}
// 10、基数排序 稳定 O(n + k) [ O(n + k), O(n + k) ]
// 基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。
#include <vector>
using namespace std;
void radixSort(vector<int>& arr) {
int n = arr.size();
//计算最大值的位数
int max = *max_element(arr.begin(), arr.end());
int digit = 0;
int base = 1;
while (max / base > 0) {
digit++;
base *= 10;
}
//需要排序的次数=位数
base = 1;
for (int i = 0; i < digit; i++) {
//统计出现次数
int bucket[10] = { 0 };
for (int j = 0; j < n; j++)
bucket[(arr[j] / base) % 10]++;
//使用累加数组
for (int j = 1; j < 10; j++)
bucket[j] += bucket[j - 1];
//根据累加数组 反向重建数组
vector<int> temp(n);
for (int k = n - 1; k >= 0; k--) {
temp[--bucket[(arr[k] / base) % 10]] = arr[k];
}
//将排好序的元素覆盖到原数组
arr.assign(temp.begin(), temp.end());
base *= 10;
}
}
C++ 10种排序方法代码汇总
最新推荐文章于 2023-12-30 16:38:57 发布