L2-算法基础-第10课 排序中

排序

归并排序

归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。作为一种典型的分而治之思想的算法应用,归并排序的实现由两种方法

  • 算法步骤

    • 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
    • 设定两个指针,最初位置分别为两个已经排序序列的起始位置;比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
    • 重复步骤 3 直到某一指针达到序列尾;将另一序列剩下的所有元素直接复制到合并序列尾。

分治的过程


合并的过程



算法分析

  • 最佳情况:
  • 最差情况:
  • 平均情况:

示例代码

#include using namespace std;const int MAXN = 5e5 + 1;int n;int a[MAXN];void merge(int arr[], int start, int mid, int end){  int len = end - start + 1;    int *tmp = new int[len];   int ai = start;    int bi = mid + 1; int ti = 0;    while(ai <= mid && bi <=end) {      if(arr[ai] <= arr[bi]) {            tmp[ti++] = arr[ai++];     } else {            tmp[ti++] = arr[bi++];     }   }   while(ai <= mid)        tmp[ti++] = arr[ai++]; while(bi <= end)        tmp[ti++] = arr[bi++]; for(int i = 0; i < len; i++) {        arr[start + i] = tmp[i];  }   delete [] tmp;}void msort(int arr[], int start, int end){   if(start >= end)        return; int mid  = (start + end) / 2; msort(arr, start, mid); msort(arr, mid + 1, end);  merge(arr, start, mid, end);}int main(){    scanf("%d", &n);  for(int i = 0; i < n; i++) {      scanf("%d", &a[i]);   }   msort(a, 0, n-1);   for(int i = 0; i < n; i++) {      printf("%d ", a[i]);  }   return 0;}

快速排序

  • 算法步骤

    • 从数列中挑出一个元素,称为 "基准"(pivot);
    • 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
    • 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;

快速排序的最坏运行情况是O(n²),比如说顺序数列的快排。但它的平摊期望时间是O(n log n) ,且O(n log n)记号中隐含的常数因子很小,比复杂度稳定等于O(n log n)的归并排序要小很多。所以,对绝大多数顺序性较弱的随机数列而言,快速排序总是优于归并排序。


算法分析

  • 最佳情况:
  • 最差情况:
  • 平均情况:

示例代码

#include using namespace std;//#define DEBUG#ifdef DEBUG#define debug(format, ...) printf("%d: "format, __LINE__, ##__VA_ARGS__)#else#define debug(format, ...)#endifint n;long long a[1000008];void qsort(int start, int end){  int mid = a[(start + end) / 2];   int left = start, right = end;    int tmp;    if(left >= right)       return; while(left <= right) {      while(a[left] < mid)         left++;       while(a[right] > mid)            right--;        if(left <= right) {         tmp = a[left];         a[left] = a[right];            a[right] = tmp;            left++;           right--;        }   }   if(start < right)        qsort(start, right);    if(left < end)       qsort(left, end);}int main(){   scanf("%d", &n);  for(int i = 0; i < n; i++)    {       scanf("%d", &a[i]);   }   qsort(0, n-1);  for(int i = 0; i < n; i++)    {       printf("%d ", a[i]);  }   return 0;}

堆排序

堆排序可以说是一种利用堆的概念来排序的选择排序。分为两种方法:大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列;

  • 算法步骤创建一个堆 H[0……n-1];把堆首(最大值)和堆尾互换;把堆的尺寸缩小 1,并调用 shift_down(0),目的是把新的数组顶端数据调整到相应位置;重复步骤 2,直到堆的尺寸为 1。

算法分析

  • 最佳情况:T(n) = O(nlogn)
  • 最差情况:T(n) = O(nlogn)
  • 平均情况:T(n) = O(nlogn)

参考代码

#include #include using namespace std;int n;int a[1000008];void max_heapify(int arr[], int start, int end){   int parent = start;    int child = parent * 2 + 1;   while (child <= end)  {     if (child + 1 <= end && arr[child] < arr[child + 1])               child++;      if (arr[parent] > arr[child])            return;     else {          swap(arr[parent], arr[child]);          parent = child;            child = parent * 2 + 1;       }   }}void heap_sort(int arr[], int len){   for (int i = len / 2 - 1; i >= 0; i--)     max_heapify(arr, i, len);   for (int i = len - 1; i > 0; i--) {     swap(arr[0], arr[i]);       max_heapify(arr, 0, i - 1); }}int main(){    scanf("%d", &n); for(int i = 0; i < n; i++) {      scanf("%d", &a[i]);   }   heap_sort(a, n);    for(int i = 0; i < n; i++) {      printf("%d ", a[i]);  }}

计数排序

计数排序的核心在于把输入的数据值转化为键存储在额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。


桶排序

桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。

元素分布在桶中:


然后,元素在每个桶中排序:


基数排序

基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。

image

基数排序、计数排序、桶排序,这三种排序算法都利用了桶的概念,但对桶的使用方法上有明显差异:

  • 基数排序根据键值的每位数字来分配桶;
  • 计数排序中,每个桶只存储单一键值;
  • 桶排序中,每个桶存储一定范围的数值。

P1271 【深基9.例1】选举学生会

题目描述

学校正在选举学生会成员,有 n(n≤999) 名候选人,每名候选人编号分别从 1 到 n,现在收集到了 m(m<=2000000) 张选票,每张选票都写了一个候选人编号。现在想把这些堆积如山的选票按照投票数字从小到大排序。输入 n 和 m 以及 m 个选票上的数字,求出排序后的选票编号。

输入格式

输出格式

输入输出样例

输入 #1复制

5 102 5 2 2 5 2 2 2 1 2

输出 #1复制

1 2 2 2 2 2 2 2 5 5

直接桶排序代码

#include using namespace std;const int  MAXN = 1002;int a[MAXN];int n, m;int main(){ int tmp;    scanf("%d %d", &n, &m);   for(int i = 1; i <= m; i++) {        scanf("%d", &tmp);        a[tmp]++; }   for(int i = 1; i <= n; i++) {        for(int j = 1; j <= a[i]; j++)           printf("%d ", i); }   return 0;}

总结

image

n: 数据规模 k: “桶”的个数 In-place: 占用常数内存,不占用额外内存 Out-place: 占用额外内存

题单

  • P1271 【深基9.例1】选举学生会
  • P1177 【模板】快速排序
  • P1923 【深基9.例4】求第 k 小的数
  • P1059 明明的随机数
  • P1093 奖学金
  • P1781 宇宙总统
  • P2676 [USACO07DEC]Bookshelf B
  • P1116 车厢重组
  • P1152 欢乐的跳
  • P1068 分数线划定
  • P5143 攀爬者
  • P1104 生日
  • P1012 拼数

云帆优培订阅号:

云帆优培服务号:

云帆优培老师联系方式:

云帆老师

微信:

云帆优培介绍

1177: 按要求排序(指针专题)_L2算法基础第10课 排序中相关推荐

  1. 分支定界算法在中学排课问题中的应用

    分支定界算法在中学排课问题中的应用 摘要:在本文中我们主要研究了带约束有教案的中学排课程表问题.首先我们得到了有关该问题的中学课程表必须满足的几个条件,因为该排课程表问题是一个NP难解的问题,因此该问 ...

  2. 算法基础:常用的排序算法知识笔记

    1.算法外排序分类 2.冒泡排序 冒泡排序(Bubble Sort)属于交换排序,它的原理是:循环两两比较相邻的记录,如果反序则交换,直到没有反序的记录为止. 实现算法: /** * 冒泡排序优化后的 ...

  3. 1177: 按要求排序(指针专题)_数据结构 8 基础排序算法详解、快速排序的实现、了解分治法...

    快速排序 快速排序与冒泡排序一样,同样是属于 交换排序 叫做快速排序也是有原因的.因为它采用了 分治法的概念 其中最重要的一个概念就是 基准元素 冒泡排序每一轮将一个最大的元素挑选出并移动到右侧. 分 ...

  4. raptor五个数排序流程图_经典算法系列之:选择排序

    1.前言 算法,在计算机中的地位,就相当于人类大脑的决策中枢系统,哪怕最简单的算法,其精妙的思维方式,都可以让人开启一扇新的视窗. 算法,它不仅仅只是狭义的用来解决计算机科学领域的问题,更是一种&qu ...

  5. java数据结构与算法基础(二)-排序

    八种常见的排序算法 八种算法分为五大类 1. 交换排序 冒泡排序 快速排序 2. 插入排序 直接插入排序 希尔排序 3. 选择排序 简单选择排序 堆排序 5. 归并排序 6. 基数排序 1. 冒泡排序 ...

  6. 算法基础——冒泡与选择排序

    冒泡排序: 一种交换排序,两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止. 例如4个数排序 #include<stdio.h> int main() { int ar[5 ...

  7. 算法基础之贪心:排序不等式、绝对值不等式、推公式

    文章 1.排序不等式 1.1.排队打水 2.绝对值不等式 2.1.货仓选址 3.推公式 3.3.耍杂技的牛 1.排序不等式 1.1.排队打水 #include <iostream> #in ...

  8. 经典算法应用之七----10亿数据中取最大的100个数据

    给出三种思路,仅供参考.. 1.思路一:根据快速排序划分的思想,每次分割之后只考虑比轴大的一部分,知道比轴大的一部分在比100多的时候,采用传统排序算法排序,取前100个. step1:递归对所有数据 ...

  9. 最长子序列和 动态规划python_算法基础之python实现动态规划中数字三角形和最长上升子序列问题...

    数字三角形问题:python 问题描述:函数 问题分析:spa 程序代码:(递归法和动归法)code # -*- coding: utf-8 -*- """ Create ...

最新文章

  1. 机加工程序工时程序_准终工时、人工工时、机器工时,十个工程师九个会弄错...
  2. Transactional Replication2:在Subscriber中,主键列是只读的
  3. java 包装类缺点_Java 自动拆箱和自动装箱学习笔记
  4. 60.Linux/Unix 系统编程手册(下) -- SOCKET: 服务器设计
  5. 更新sdk_即构ZegoLiveRoom SDK版本更新,新增多项功能及自定义设置
  6. 项目复盘内容及注意事项
  7. python掷骰子实验代码_Python Tkinter实例——模拟掷骰子
  8. VsCode+PHP开发 推荐插件
  9. Android 5.0、6.0、7.0、8.0、9.0 新特性,DownloadManager踩坑记
  10. 算法----火柴拼正方形
  11. win32获取本地ip
  12. 合并两个或者多个select结果集
  13. 孙子定理(中国剩余定理)
  14. 小米5升级Linux内核,小米5 刷机LineageOS 14.1的详细教程
  15. Kubernetes — CNI 网络插件规范
  16. Linux琐屑网络设置细致分解
  17. python是个什么东西刷爆朋友圈_五星好评!这门Python神作刷爆朋友圈
  18. 32位微型计算机原理接口技术及其应用,32位微型计算机原理·接口技术及其应用...
  19. IT规划及管理讨论,请各位凭借自己的理解踊跃发言(可选择回答^^)
  20. 虚拟机没有网络还没有网络图标!!!

热门文章

  1. win11网络怎么优化 Windows11优化网速的步骤教程
  2. swagger 使用
  3. php 音频上传大小限制,WordPress最大上传文件大小限制修改 | Stay Curious
  4. python分割文件为小文件_Python实现将一个大文件按段落分隔为多个小文件的简单操作方法...
  5. (转) MCU实战经验---多种的按键处理
  6. vue 初始化请求例子_Vue实例初始化
  7. gateway动态路由_微服务中的网关技术:Gateway
  8. Unity Physics.Raycast踩坑
  9. 微信小程序 webview 传递URL中含有特殊字符-,=
  10. opencv之CmakeLists.txt配置