十大排序算法C++实现
本章对十大排序算法进行C++代码实现,可以前往力扣进行验证,其中冒泡,选择,插入,快排会超时。
Leetcode912数组排序
排序稳定性指的是:所有相等的数经过某种排序后,仍能保持排序前的相对次序,这种排序方法是稳定的。
例如:arr = [5 8 5 2 9]使用选择排序是不稳定的,因为前面的5跑到后面去了
贴两张图归类一下
冒泡法
vector<int> sortArray(vector<int>& nums) {//冒泡法
for(int i=0;i<nums.size()-1;i++){
for(int j=0;j<nums.size()-i-1;j++){
if(nums[j]>nums[j+1]){
int temp=nums[j];
nums[j]=nums[j+1];
nums[j+1]=temp;
}
}
}
return nums;
}
冒泡法优化
vector<int> sortArray(vector<int>& nums) {//冒泡法优化
int n = nums.size();
bool swapped; // 标志位,用于检测是否发生了交换
for (int i = 0; i < n - 1; i++) {
swapped = false; // 初始化标志位为假
for (int j = 0; j < n - i - 1; j++) {
if (nums[j] > nums[j + 1]) {
swap(nums[j], nums[j + 1]); // 交换元素位置
swapped = true; // 设置标志位为真
}
} // 如果在一轮遍历中没有发生交换,说明数组已经有序,提前退出
if (!swapped) {
break;
}
}
return nums;
}
快速排序
取第一个数为基准值,小的放左边,大的放右边,重复直到i==j,再继续选取基准值
vector<int> sortArray(vector<int>& nums) {//快速排序
Quick(nums,0,nums.size()-1);
return nums;
}
void Quick(vector<int>& nums,int start,int end){
if(start>=end)return;
int i=start;
int j=end;
int baseval=nums[start];
while(i<j){
while(i<j&&nums[j]>=baseval){// 从右向左找比基准数小的数
j--;
}
if(i<j){
nums[i]=nums[j];
i++;
}
while(i<j&&nums[i]<=baseval){// 从左向右找比基准数大的数
i++;
}
if(i<j){
nums[j]=nums[i];
j--;
}
}
nums[i]=baseval;//i和j相等,可以分区间了
Quick(nums,start,i-1);
Quick(nums,i+1,end);
}
快排优化 随机选择基准值、插入排序优化、三数取中法
vector<int> sortArray(vector<int>& nums) {
Quick(nums, 0, nums.size() - 1);
return nums;
}
void Quick(vector<int>& nums, int start, int end) {
if (start >= end) return;
if (end - start + 1 <= 10) { // 切换到插入排序
InsertionSort(nums, start, end);
return;
}
// 随机选择基准值
int pivotIdx = start + rand() % (end - start + 1);
// 选完交换一下
swap(nums[start], nums[pivotIdx]);
int i = start;
int j = end;
int baseval = nums[start];
while (i < j) {
while (i < j && nums[j] >= baseval) j--;
while (i < j && nums[i] <= baseval) i++;
if (i < j) swap(nums[i], nums[j]);
}
nums[start] = nums[i];
nums[i] = baseval;
Quick(nums, start, i - 1);
Quick(nums, i + 1, end);
}
void InsertionSort(vector<int>& nums, int start, int end) {
for (int i = start + 1; i <= end; i++) {
int key = nums[i];
int j = i - 1;
while (j >= start && nums[j] > key) {
nums[j + 1] = nums[j];
j--;
}
nums[j + 1] = key;
}
}
插入排序
对近有序的序列更高效,时间复杂度更接近O(n)
```cpp
vector<int> sortArray(vector<int>& nums) {**//插入排序,对近有序的序列更高效,时间复杂度更接近O(n)**
for(int i=1;i<nums.size();i++){
int j=i-1;
int key=nums[i];
while(j>=0&&nums[j]>key){
nums[j+1]=nums[j];
j--;
}
nums[j+1]=key;
}
return nums;
}
希尔排序
对数组执行多次间隔的插入排序,也叫最小增量排序,通常除以2,间隔排序,最后来一次总插入排序
vector<int> sortArray(vector<int>& nums) {//希尔排序
int len=nums.size();
int increasement = len;
int i, j, k;
while (increasement > 1) {
// 确定分组的增量
increasement = increasement / 2 ;//增量为2
for (i = 0; i < increasement; i++) {
for (j = i + increasement; j < len; j += increasement) {
if (nums[j] < nums[j - increasement]) {
int temp = nums[j];
for (k = j - increasement; k >= 0 && temp < nums[k]; k -=increasement) {
nums[k + increasement] = nums[k];
}
nums[k + increasement] = temp;
}
}
}
}
return nums;
}
希尔排序经典写法
vector<int> sortArray(vector<int>& nums) {//希尔排序,更经典的写法
int n = nums.size();
for (int gap = n / 2; gap > 0; gap /= 2) {
for (int i = gap; i < n; i++) {
int temp = nums[i];
int j = i;
while (j - gap >= 0 && nums[j - gap] > temp) {
nums[j] = nums[j - gap];
j -= gap;
}
nums[j] = temp;
}
}
return nums;
}
选择排序
vector<int> sortArray(vector<int>& nums) {//选择排序
for(int i=0;i<nums.size();i++){
int min=i;
for(int j=i+1;j<nums.size();j++){
if(nums[min]>nums[j]){
min=j;
}
}
if(i!=min){
swap(nums[min],nums[i]);//优化,当min和i不相等才交换,影响不大
}
}
return nums;
}
归并排序(分治法)
有序数组A+有序数组——>有序数组A+B,将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。代价是需要额外的内存空间。
vector<int> sortArray(vector<int>& nums) {//归并排序
mergeSort(nums,0,nums.size()-1);
return nums;
}
void mergeSort(std::vector<int>& nums, int left, int right) {
if (left < right) {//只有一个数字的时候不再分割子序列
int mid = left + (right - left) / 2;
mergeSort(nums, left, mid);
mergeSort(nums, mid + 1, right);
merge(nums, left, mid, right);
}
}
void merge(std::vector<int>& nums, int left, int mid, int right) {
int n1 = mid - left + 1;
int n2 = right - mid;
std::vector<int> leftArr(n1);
std::vector<int> rightArr(n2);
for (int i = 0; i < n1; i++) {
leftArr[i] = nums[left + i];
}
for (int i = 0; i < n2; i++) {
rightArr[i] = nums[mid + 1 + i];
}
int i = 0, j = 0, k = left;
while (i < n1 && j < n2) {
if (leftArr[i] <= rightArr[j]) {
nums[k] = leftArr[i];
i++;
} else {
nums[k] = rightArr[j];
j++;
}
k++;
}
while (i < n1) {
nums[k] = leftArr[i];
i++;
k++;
}
while (j < n2) {
nums[k] = rightArr[j];
j++;
k++;
}
}
计数排序
元素值即下标
vector<int> sortArray(std::vector<int>& nums) {//计数排序
if (nums.empty()) {
return nums;
}
// 找到数组中的最大值和最小值
int max_num = *std::max_element(nums.begin(), nums.end());
int min_num = *std::min_element(nums.begin(), nums.end());
// 计算计数数组的大小
int range = max_num - min_num + 1;
// 创建计数数组并初始化为0
vector<int> count(range, 0);
// 统计每个元素的出现次数
for (int num : nums) {
count[num - min_num]++;
}
// 根据计数数组重新构建排序后的数组
int index=0;
for(int i=0;i<range;i++){
while(count[i]>0){
nums[index]=i + min_num;
index++;
count[i]--;
}
}
return nums;
}
桶排序
数组分配到若干桶,各自排序后返回
vector<int> sortArray(vector<int>& nums) {//桶排序
if (nums.empty()) {
return nums;
}
// 找到数组中的最大值和最小值
int max_num = *std::max_element(nums.begin(), nums.end());
int min_num = *std::min_element(nums.begin(), nums.end());
// 计算计数数组的大小
// 计算桶的数量,每个桶的范围是 (max_num - min_num + 1) / nums.size(),加 1 是为了包括最大值
int bucket_count = (max_num - min_num + 1) / nums.size() + 1;
// 创建桶并初始化为空
vector<vector<int>> buckets(bucket_count);
// 将元素分配到对应的桶中
for (int num : nums) {
int bucket_index = (num - min_num) / nums.size();
buckets[bucket_index].push_back(num);
}
// 对每个桶中的元素进行排序(可以使用其他排序算法,如插入排序)
for (vector<int>& bucket : buckets) {
sort(bucket.begin(), bucket.end());
}
// 合并各个桶的排序结果
nums.clear();
for (const vector<int>& bucket : buckets) {
nums.insert(nums.end(), bucket.begin(), bucket.end());
}
return nums;
}
基数排序
数字逐位比较。个位数排序,十位数排序,百位数排序。。。以此类推
vector<int> sortArray(vector<int>& nums) {//基数排序
int n = nums.size();
vector<int> arr(n);
//获取数组中最小值
int min = nums[0];
for (int i = 0; i < n; i++) {
min = std::min(min, nums[i]);
}
//把负数转为正数
for (int i = 0; i < n; i++) {
nums[i] -= min;
}
//基数排序
radixSort(nums);
//还原
for (int i = 0; i < n; i++) {
nums[i] += min;
}
return nums;
}
void radixSort(vector<int>& arr) {
int max = getMax(arr);
// 对每个位进行计数排序,位数从个位开始,直到最高位
for (int exp = 1; max / exp > 0; exp *= 10) {
countingSort(arr, exp);
}
}
int getMax(vector<int>& arr) {
int max = arr[0];
for (int i = 1; i < arr.size(); i++) {
max = std::max(arr[i],max);
}
return max;
}
void countingSort(vector<int>& arr, int exp) {
int n = arr.size();
vector<int> output(n); // 存储排序结果的临时数组
vector<int> count(10, 0); // 计数数组,用于统计每个位置上的数字的出现次数
// 统计每个位置上数字的出现次数
for (int i = 0; i < n; i++) {
int digit = (arr[i] / exp) % 10;
count[digit]++;
}
// 将计数数组中的值累加,确定每个数字在输出数组中的位置
for (int i = 1; i < 10; i++) {
count[i] += count[i - 1];
}
// 根据计数数组将数字放入输出数组中,从后往前才能达到基数排序的效果
for (int i = n - 1; i >= 0; i--) {
int digit = (arr[i] / exp) % 10;
count[digit]--;
output[count[digit]] = arr[i];
}
// 将输出数组拷贝回原数组
arr = output;
}
小知识:sort
函数是C++标准库提供的用于对容器中的元素进行排序的函数。底层原理通常使用一种高效的排序算法,通常是快速排序(Quicksort)或归并排序(Mergesort),取决于具体的实现和输入数据的大小。C++标准库的具体实现可能因不同的编译器和标准库版本而异。