CSP-J算法基础 计数排序

news2024/11/23 23:13:30

文章目录

  • 前言
  • 计数排序
    • 计数排序的过程
    • 总结
  • 代码实现计数排序
  • 总结


前言


计数排序

计数排序(Counting Sort)是一种线性时间复杂度的排序算法,适用于范围有限的整数排序。它通过计数每个值出现的次数,依次排列这些值。该算法不通过比较元素大小进行排序,而是根据值的分布情况完成排序。

计数排序的过程

假设我们有一个数组 [4, 2, 2, 8, 3, 3, 1],需要对它进行升序排序。

  1. 初始数组
    [4, 2, 2, 8, 3, 3, 1]

  2. 找到最大值和最小值
    计数数组大小的公式是:

在这里插入图片描述

其中:

  • 最大值 是输入数组中的最大元素;
  • 最小值 是输入数组中的最小元素;
  • 加上 1 是为了包括最大值和最小值之间的所有可能值。

这个公式确保计数数组有足够的空间来记录所有输入数组中可能的整数值的出现次数。

  • 最大值是 8,最小值是 1。因此,计数数组的大小为 8 - 1 + 1 = 8
  1. 构建计数数组

    • 创建一个大小为 8 的计数数组 count,初始时所有值为 0。即:
      [0, 0, 0, 0, 0, 0, 0, 0]
  2. 计算每个元素出现的次数

    • 遍历输入数组,并增加计数数组对应位置的值:
      • 数字 4count[4 - 1]++count 变为 [0, 0, 0, 1, 0, 0, 0, 0]
      • 数字 2count[2 - 1]++count 变为 [0, 1, 0, 1, 0, 0, 0, 0]
      • 数字 2count[2 - 1]++count 变为 [0, 2, 0, 1, 0, 0, 0, 0]
      • 数字 8count[8 - 1]++count 变为 [0, 2, 0, 1, 0, 0, 0, 1]
      • 数字 3count[3 - 1]++count 变为 [0, 2, 1, 1, 0, 0, 0, 1]
      • 数字 3count[3 - 1]++count 变为 [0, 2, 2, 1, 0, 0, 0, 1]
      • 数字 1count[1 - 1]++count 变为 [1, 2, 2, 1, 0, 0, 0, 1]

    现在,计数数组显示了输入数组中每个元素出现的次数:
    [1, 2, 2, 1, 0, 0, 0, 1]

  3. 累加计数数组

    • 修改计数数组,使其变成累计计数数组。这表示每个数字应当出现在最终数组中的位置:
      • count[1] = count[0] + count[1][1, 3, 2, 1, 0, 0, 0, 1]
      • count[2] = count[1] + count[2][1, 3, 5, 1, 0, 0, 0, 1]
      • count[3] = count[2] + count[3][1, 3, 5, 6, 0, 0, 0, 1]
      • count[4] = count[3] + count[4][1, 3, 5, 6, 6, 0, 0, 1]
      • count[5] = count[4] + count[5][1, 3, 5, 6, 6, 6, 0, 1]
      • count[6] = count[5] + count[6][1, 3, 5, 6, 6, 6, 6, 1]
      • count[7] = count[6] + count[7][1, 3, 5, 6, 6, 6, 6, 7]

    累加后的计数数组为:
    [1, 3, 5, 6, 6, 6, 6, 7]

  4. 构建排序后的数组

    • 使用计数数组将输入数组中的每个元素放到正确的位置:
      • 数字 1count[1 - 1]--,将 1 放入排序后的数组第 0 位。数组变为 [1, _, _, _, _, _, _]
      • 数字 2count[2 - 1]--,将 2 放入排序后的数组第 2 位。数组变为 [1, _, 2, _, _, _, _]
      • 数字 2count[2 - 1]--,将 2 放入排序后的数组第 1 位。数组变为 [1, 2, 2, _, _, _, _]
      • 数字 3count[3 - 1]--,将 3 放入排序后的数组第 4 位。数组变为 [1, 2, 2, _, 3, _, _]
      • 数字 3count[3 - 1]--,将 3 放入排序后的数组第 3 位。数组变为 [1, 2, 2, 3, 3, _, _]
      • 数字 4count[4 - 1]--,将 4 放入排序后的数组第 5 位。数组变为 [1, 2, 2, 3, 3, 4, _]
      • 数字 8count[8 - 1]--,将 8 放入排序后的数组第 6 位。数组变为 [1, 2, 2, 3, 3, 4, 8]
  5. 最终结果

    • 输入数组 [4, 2, 2, 8, 3, 3, 1] 被排序为 [1, 2, 2, 3, 3, 4, 8]

总结

计数排序通过创建一个计数数组来记录每个元素出现的次数,然后使用这些计数信息将元素放置在正确的位置。这个算法的时间复杂度是 O(n+k),其中 n 是输入数据的大小,k 是数据的取值范围。对于元素范围较小且数据量大的情况,计数排序表现非常出色。然而,当数据范围较大时,计数排序的空间复杂度较高,使用效果可能不理想。

代码实现计数排序

#include <stdio.h>
#include <stdlib.h>

// 计数排序函数
void countingSort(int arr[], int n) {
    int i, max = arr[0], min = arr[0];

    // 找到数组中的最大值和最小值
    for (i = 1; i < n; i++) {
        if (arr[i] > max) {
            max = arr[i];
        }
        if (arr[i] < min) {
            min = arr[i];
        }
    }

    printf("最大值: %d, 最小值: %d\n", max, min);

    // 计算计数数组的大小
    int range = max - min + 1;
    int *count = (int *)calloc(range, sizeof(int));  // 动态分配内存并初始化为0

    // 计算每个元素出现的次数
    for (i = 0; i < n; i++) {
        count[arr[i] - min]++;
    }

    // 打印计数数组
    printf("计数数组:\n");
    for (i = 0; i < range; i++) {
        printf("%d ", count[i]);
    }
    printf("\n");

    // 将计数数组累加,调整为位置索引
    for (i = 1; i < range; i++) {
        count[i] += count[i - 1];
    }

    // 打印累加后的计数数组
    printf("累加后的计数数组:\n");
    for (i = 0; i < range; i++) {
        printf("%d ", count[i]);
    }
    printf("\n");

    // 创建输出数组
    int *output = (int *)malloc(n * sizeof(int));

    // 按照计数数组的值,构建排序后的数组
    //从后向前遍历排序 
    for (i = n - 1; i >= 0; i--) {
        output[count[arr[i] - min] - 1] = arr[i];
        count[arr[i] - min]--;  // 更新计数数组
    }

    // 打印排序后的数组
    printf("排序后的数组:\n");
    for (i = 0; i < n; i++) {
        arr[i] = output[i];
        printf("%d ", arr[i]);
    }
    printf("\n");

    // 释放动态分配的内存
    free(count);
    free(output);
}

int main() {
    int arr[] = {5, 2, 2, 8, 3, 3, 1};
    int n = sizeof(arr) / sizeof(arr[0]);

    printf("原始数组:\n");
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    // 调用计数排序
    countingSort(arr, n);

    return 0;
}



总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2123142.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LVGL 控件之线条(lv_line)

目录 一、概述二、线条1、设置连接点2、自适应大小3、翻转 y 轴4、样式4.1 设置宽度4.2 末端形态 4.3 虚线5、API 函数 一、概述 线条部件只有一个组成部分&#xff1a;主体 LV_PART_MAIN。 通过一组点绘制出相连的直线&#xff0c;通过 lv_line_create 创建相应的对象。 二…

利用深度学习实现验证码识别-4-ResNet18+imagecaptcha

在当今的数字化世界中&#xff0c;验证码&#xff08;CAPTCHA&#xff09;是保护网站免受自动化攻击的重要工具。然而&#xff0c;对于用户来说&#xff0c;验证码有时可能会成为一种烦恼。为了解决这个问题&#xff0c;我们可以利用深度学习技术来自动识别验证码&#xff0c;从…

5.第二阶段x86游戏实战2-认识内存

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 工具下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1rEEJnt85npn7N38Ai0_F2Q?pwd6tw3 提…

Cesium 展示——Cesium 初始化视角在中国并加载数据(china.json)

文章目录 需求一:初始化视角在中国分析需求二:加载中国数据(china.json)需求一:初始化视角在中国 在初始化 Cesium 的 Viewer 后,视角是在美国,如何让其视角指向中国 分析 viewer.value = new Cesium.Viewer(cesiumContainer.value, {homeButton

redis基本数据结构-string

文章目录 1. redis的string数据结构2. 常见的业务场景2.1 缓存功能案例讲解背景优势解决方案代码实现 2.2 计数器案例讲解背景优势解决方案代码实现 2.3 分布式锁案例讲解背景优势解决方案代码实现 2.4 限流案例讲解背景优势解决方案代码实现 2.5 共享session案例讲解背景优势解…

Docker突然解封,直接拉取!

文章目录 Docker突然解封&#xff0c;直接拉取&#xff01;封禁的原因是什么&#xff1f;解封的原因是什么&#xff1f;封禁对开发的影响经验教训 最近开始公众号文章也开始同步更新了&#xff0c;对Java、大数据、人工智能、开发运维相关技术分享&#xff0c;文章对您有用的话…

Linux 8250串口控制器

1 8250串口类型的识别 Intel HW都使用DesignWare 8250&#xff1a; drivers/mfd/intel-lpss-pci.c drivers/tty/serial/8250/8250_dw.c IIR寄存器的高2位bit7、bit6用来识别8250串口的类型&#xff1a; 0 - 8250&#xff0c;无FIFO 0 - 并且存在SCR&#xff08;Scratch registe…

SQL优化(二)统计信息

收集统计信息 数据库的统计信息非常重要&#xff0c;如果没有正确地收集表的统计信息&#xff0c;或者没有及时地更新表的统计信息&#xff0c;SQL就有可能走错执行计划&#xff0c;也就会出现性能问题。 统计信息主要分为表的统计信息、列的统计信息、索引的统计信息、系统的…

TeamTalk数据库代理服务器

文章目录 main函数主流程关键步骤线程池redis缓存未读消息计数未读消息计数-单聊未读消息计数-群聊 群成员管理 main函数主流程 关键步骤 初始化epoll 线程池数据入口 reactor CProxyConn::HandlePduBuf异步task任务封装&#xff0c;把任务放入线程池&#xff1b;线程池里的…

【AI学习】AI科普:专有名词介绍

这里是阿川的博客&#xff0c;祝您变得更强 ✨ 个人主页&#xff1a;在线OJ的阿川 &#x1f496;文章专栏&#xff1a;AI入门到进阶 &#x1f30f;代码仓库&#xff1a; 写在开头 现在您看到的是我的结论或想法&#xff0c;但在这背后凝结了大量的思考、经验和讨论 目录 1.AI序…

TCP通信三次握手、四次挥手

前言 前面我说到了&#xff0c;UDP通信的实现&#xff0c;但我们经常说UDP通信不可靠&#xff0c;是因为他只会接收和发送&#xff0c;并不会去验证对方收到没有&#xff0c;那么我们说TCP通信可靠&#xff0c;就是因为他会进行验证接收端是否能够接收和发送&#xff0c;并且只…

给大家推荐好用的AI网站

地址&#xff1a;https://ai.ashuiai.com/auth/register?inviteCode8E8DIC1QCR 个人觉得挺好用的&#xff0c;可以免费&#xff0c;免费有限制次数&#xff0c;也可以会员升级200永久免费&#xff0c;我用的200永久免费。 可以在国内使用以下ai模型 回答问题更智能&#xff…

计算机毕业设计 校内跑腿业务系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

分享6个我喜欢的常用网站,来看看有没有你感兴趣的!

分享6个我自己很喜欢的常用网站&#xff0c;平时工作生活中经常会打开&#xff0c;来看看有没有你感兴趣的&#xff01; 1.Crazygames crazygames.com/ 一个超赞的在线小游戏平台&#xff0c;上面有超过7000种游戏任你选。不管你喜欢冒险、解谜、闯关&#xff0c;还是装扮、赛…

概要设计例题

答案&#xff1a;A 知识点&#xff1a; 概要设计 设计软件系统的总体结构&#xff1a;采用某种方法&#xff0c;将一个复杂的系统按照功能划分成模块&#xff1b;确定每个模块的功能&#xff1b;确定模块之间的调用关系&#xff1b;确定模块之间的接口&#xff0c;即模块之间…

返工(Rework)与返修(Repair)有何不一样

IATF 16949 汽车业质量管理体系,以客户需求为基础,组织透过相关单位了解客户需求后,向内部流程展开,目的是确保从研发到出货每个环节都能满足客户需求,同时管控制造过程的效率及良率,使产线能够稳定及准时交货给客户。 IATF 16949 条文中,针对「返工(Rework)」与「返修(…

linux工具的使用

1.yum和apt的概念与使用 yum 和 apt 是两种不同的包管理工具&#xff0c;用于在 Linux 系统上管理软件包。 yum (Yellowdog Updater, Modified) 发行版: 用于基于 RPM 的发行版&#xff0c;如 CentOS、RHEL 和 Fedora。基本命令: 更新包列表: sudo yum update安装包: sudo y…

Sky Takeaway

软件开发整体介绍 软件开发流程 角色分工 软件环境 苍穹外卖 项目介绍 定位&#xff1a;专门为餐饮企业定制的一款软件产品 技术选型 前端环境搭建 阅读readme文档 nginx.exe放入无中文目录运行并启动 后端环境搭建 项目结构 Nginx反向代理 优点 配置 Nginx反向代理 负…

QXlsx编译静态库-配置为Qt模块

Qt读写Excel–QXlsx编译为静态库-配置为Qt模块&#x1f346; 文章目录 Qt读写Excel--QXlsx编译为静态库-配置为Qt模块&#x1f346;[toc]1、概述&#x1f954;2、准备工作&#x1f955;3、配置环境&#x1f33d;4、加载QXlsx静态库&#x1f952; &#x1f449;QXlsx使用&#x…

《深度学习》OpenCV 高阶 图像金字塔 用法解析及案例实现

目录 一、图像金字塔 1、什么是图像金字塔 2、图像金字塔作用 1&#xff09;金字塔尺度间的图像信息补充 2&#xff09;目标检测与识别 3&#xff09;图像融合与拼接 4&#xff09;图像增强与去噪 5&#xff09;图像压缩与编码 二、用法解析 1、向下采样 1&#xff09;概念…