【C/C++算法】高级排序算法

news/2024/11/25 21:30:33/

目录

一、希尔排序

二、堆排序

三、归并排序

四、快速排序

五、计数排序

六、基数排序


一、希尔排序

思路:

  • 希尔排序是属于插入排序,先对数组进行预排序,使数组相对有序,再进行直接插入排序
  • 预排序的gap值可以取任意>=1的值,经测试效率最高的 gap取值为 gap/3 + 1,初始值为size
  • 初始的有序度越高的数组,进行插入排序的效率就越高

时间复杂度:不稳定,与数组的初始有序度及gap的计算方法有关,介于O(n) ~ O(n^2)

void ShellSort(int* arr, int size) 
{int gap = size;while (gap > 1) {gap = gap / 3 + 1;int i = 0;for (i = 0; i < size - gap; ++i) {int end = i;int tmp = arr[end + gap];while (end >= 0 && tmp < arr[end]) {arr[end + gap] = arr[end];end -= gap;}arr[end + gap] = tmp;}}
}

二、堆排序

思路:

  • 将数组建堆,输出要升序就建大根堆,输出要降序就建小根堆
  • 将堆顶的元素与与最后一个元素交换,从堆顶进行向下调整,调整的范围为size依次递减
  • 堆可视为顺序存储的完全二叉树

时间复杂度:稳定,每次从堆顶向下调整为 lg(n),总复杂度为 n * lg(n)

#include <stdio.h>void Swap(int* arr, int pi, int pj) 
{int tmp = arr[pi];arr[pi] = arr[pj];arr[pj] = tmp;
}//大根堆:升序
//小根堆:降序
void AdjustDown(int* arr, int parent, int size) 
{int child = parent * 2 + 1;while (child < size) {if (child + 1 < size && arr[child + 1] > arr[child]) ++child;if (arr[parent] < arr[child]) {Swap(arr, parent, child);parent = child;child = parent * 2 + 1;}else {break;}}
}void HeapSort(int* arr, int size) 
{int parent = (size - 2) / 2;int i;for (i = parent; i >= 0; --i) {AdjustDown(arr, i, size);   //构建大根堆}while (size) {Swap(arr, 0, --size);AdjustDown(arr, 0, size);}}

三、归并排序

思路:

  • 递归思想,将一个数组从中间分为两个子数组,分别对两个子数组递归进行归并排序
  • 子数组的最小长度为2或3,此时设置4个角标,begin1,end1,begin2,end2
  • begin1、end1代表左子数组的首尾,begin2、end2代表右子数组的首尾
  • 同时遍历左右两个子数组,对比begin1和begin2对应的值,小的存入count数组
  • 遍历结束之后,将count按地址按字节拷贝到arr,空间换时间

时间复杂度:稳定,递归的复杂度为 lg(n),每个数都会遍历一次,总复杂度为 n * lg(n)

void _MergeSort(int* arr, int begin, int end, int* count) 
{if (begin >= end) return;int mid = (begin + end) / 2;_MergeSort(arr, begin, mid, count);_MergeSort(arr, mid + 1, end, count);int begin1 = begin, end1 = mid;int begin2 = mid + 1, end2 = end;int i = begin;while (begin1 <= end1 && begin2 <= end2) {if (arr[begin1] < arr[begin2]) count[i++] = arr[begin1++];else count[i++] = arr[begin2++];}while (begin1 <= end1) {count[i++] = arr[begin1++];}while (begin2 <= end2) {count[i++] = arr[begin2++];}memcpy(arr + begin, count + begin, sizeof(int) * (end - begin + 1));
}void MergeSort(int* arr, int size) 
{int* count = (int*)malloc(sizeof(int) * size);int mid = size / 2;_MergeSort(arr, 0, mid, count);_MergeSort(arr, mid + 1, size - 1, count);free(count);count = NULL;
}

四、快速排序

思路:

  • 递归思想,数组取一个关键字key值,将比key小的数排在key左边,比key大的数排在key右边
  • 然后从key值处将数组切分为两个子数组,再分别对两个子数组进行快排递归
  • key值取首位、中间位、末尾的中位数,提高效率
  • 前后指针法,先将中位数关键字放在首位,后指针的值每次都与首位关键字比较,最后返回front
  • 为提高效率,可在end - begin < n 时使用直接插入排序而放弃快排递归,n根据数据量取值

时间复杂度:不稳定,平均复杂度是O(n * lg(n))

void Swap(int* arr, int pi, int pj) 
{int tmp = arr[pi];arr[pi] = arr[pj];arr[pj] = tmp;
}//取中位数
int MidNum(int* arr, int l, int m, int r) 
{if (arr[l] < arr[r]) {if (arr[m] < arr[l])return l;else if (arr[m] < arr[r])return m;elsereturn r;}else {if (arr[m] > arr[l])return l;else if (arr[m] > arr[r])return m;elsereturn r;}
}//前后指针法
int PtrPrt(int* arr, int begin, int end) 
{int mid = (begin + end) / 2;int keyi = MidNum(arr, begin, mid, end);Swap(arr, keyi, begin);int front = begin;int back = begin + 1;while (back <= end) {if (arr[back] < arr[begin] && ++front != back) Swap(arr, front, back);++back;}Swap(arr, begin, front);return front;
}void QuickSort(int* arr, int begin, int end) 
{if (begin >= end) return;int keyi = PtrPrt(arr, begin, end);QuickSort(arr, begin, keyi - 1);QuickSort(arr, keyi + 1, end);
}

五、计数排序

思路:

  • 哈希思想,用空间换时间,找到arr数组中的最大值max和最小值min
  • 创建(max - min + 1)个元素的count数组并置零,用于统计arr数组中每个数字的出现次数
  • 遍历原数组,count[arr[i] - min]++,可用count记录原数组中每个数出现的次数
  • 再遍历count数组,从小到大将数值写入arr数组中,完成排序
  • 适用于arr数组中的最大值和最小值相差不大的情况

复杂度:不稳定,介于O(n) ~ O(n^2)

void CountSort(int* arr, int size) 
{int min = arr[0], max = arr[0];int i;for (i = 0; i < size; ++i) {if (arr[i] < min) min = arr[i];if (arr[i] > max) max = arr[i];}int* count = (int*)malloc(sizeof(int) * (max - min + 1));memset(count, 0, max - min + 1);for (i = 0; i < size; ++i) {count[arr[i] - min]++;}int j = 0;for (i = 0; i < max - min + 1; ++i) {while (count[i]--) {arr[j++] = i + min;}}
}

六、基数排序

思路:

  • 为了代码方便使用C++,利用队列进行数据收发
  • 创建一个队列数组,数组大小为10,每个元素都是一个队列,存储取模为 1 ~ 9 的数
  • 从低位到高位进行数据收发,完成排序
  • 适用于数据位数不高的情况

时间复杂度:与最大值的位数K有关,K * O(n),所以时间复杂度为O(n)

#include <iostream>
#include <queue>
using namespace std;#define K 3     //数组中最大数据的位数
#define RADIX 10//定义基数
queue<int> g_q[RADIX];int GetKey(int val, int k) 
{int key = val % 10;while (k--) {val /= 10;key = val % 10;}return key;
}void Distribute(int* arr, int left, int right, int k) 
{for (int i = left; i <= right; ++i) {int key = GetKey(arr[i], k);g_q[key].push(arr[i]);}
}void Collect(int* arr) 
{int j = 0;for (int i = 0; i < RADIX; ++i) {while (!g_q[i].empty()) {arr[j++] = g_q[i].front();g_q[i].pop();}}
}void RadixSort(int* arr, int size) 
{for (int i = 0; i < K; ++i) {Distribute(arr, 0, size - 1, i);    //分发数据Collect(arr);       //收集数据}
}

http://www.ppmy.cn/news/586550.html

相关文章

卤煮花生米的制作过程(高压锅版)

去皮花生米和黄豆&#xff08;比例2:1或3:1&#xff09;&#xff0c;花椒、八角少许&#xff0c;洗净&#xff0c;放入高压锅&#xff0c;清水没过&#xff0c;加盖&#xff0c;大火烧至水开&#xff0c;换小火再烧5分钟后关火。高压气自然放光之后&#xff0c;开盖&#xff0c…

选择高压锅参考?

知乎精选&#xff1a;https://zhuanlan.zhihu.com/p/269718252

CF865D Buy Low Sell High

题目翻译&#xff1a;已知接下来N天的股票价格,每天你可以买进一股股票,卖出一股股票,或者什么也不做.N天之后你拥有的股票应为0,当然,希望这N天内能够赚足够多的钱。 一开始想用动态规划单调队列优化&#xff0c;但是最坏情况下单调队列没有优化效果&#xff0c;时间复杂度还…

js设计模式-状态模式-示例(高压锅状态)

<template><div class"cooker"><img src"../assets/gaoyaguo.png" alt"." /><div class"flex typeName"><div>状态:{{ typeName }}</div><div>描述:{{ desction }}</div></div>…

Q345qE钢板价格.Q345qD桥梁板价格.Q345qC价格都多少.区别多大

Q345qE钢板价格.Q345qD桥梁板价格.Q345qC价格都多少.区别多大 Q345qE.Q345qD.Q345qC桥梁板现货和期货的报价 看yong 户 名 Q345qE.Q345qD.Q345qC桥梁板表示方法 如Q字母&#xff1a;桥梁用钢屈服强度的“屈”字的汉语拼音首位字母;如规定最小屈服强度数值,345单位MPa;Q&#x…

廉价版iPhone X曝光:A12处理器+全面屏设计,价格便宜一半

对于手机来说&#xff0c;小伙伴们比较关注&#xff0c;其中关注最多的无非就是iPhone 系列了&#xff0c;然而对于明年苹果将发布三款新 iPhone 已经不是什么新闻了&#xff0c;关键的是其外观设计和具体价格。 许多家消息都在进行猜测&#xff0c;认为下一代 iPhone 将抛弃传…

同事说关键字查询用Mysql,我上去就是一个高压锅,用ElasticSearch不香吗?

hello&#xff0c;hello这里是富贵同学&#xff0c;马上过年啦&#xff0c;提前祝大家新年快乐&#xff01;&#xff01;&#xff01; 如题所示&#xff0c;假如说我们要做一个搜索框的功能&#xff0c;类似于csdn的搜索功能&#xff1a; 当我们用关键字查询的时候如果用mysq…

3DR10P5-6X/315Y/00M减压阀是REXROTH电控先导式三通减压阀

前言&#xff1a;3DR10P5-6X/315Y/00M减压阀是REXROTH电控先导式三通减压阀&#xff0c;具有压力限制执行器&#xff0c;可限制次级油路的压力&#xff0c;节流元件可以改变局部阻力&#xff0c;从而改变流量和动能&#xff0c;引起不同压力损失&#xff0c;达到减压的目的。 基…