C++ 10种排序方法代码汇总


// 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;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值