详解计数排序算法原理与使用方法

算法概述

计数排序是一种非比较排序算法,用于将元素排列在特定顺序。计数排序可以用于整数和某些浮点数。它的基本思想是在需要排序的数组中,如果数组中的最小值是k,最大值是j,那么可以创建一个计数器数组来计算原始数组中每个数值的出现次数。依此可以遍历计数器数组并按计数器的计数值直接填充输出数组,从而生成排序后的数组。具体而言,计数排序由以下 3 个实质性部分组成:

  1. 计数数组: 长度为需要排序的数字范围,遍历待排序序列,将序列中所有的数字按次数放入对应下标的计数数组。
  2. 累加数组: 对计数数组进行逐个累和,可以得到每个数字应该排序的下标。
  3. 排序数组: 根据累加数组,将待排序序列中的每个元素按顺序放入这个新的数组里。

算法流程

以整数一维数组排序为例,算法流程如下:

  1. 扫描一遍序列找到最大值和最小值,取区间长度len=max-min+1,为计数数组的长度。
  2. 定义计数数组c,一遍扫描序列,将出现的整数计数记录在相应的计数数组位置上,c[i]-=min,其中c[i]表示i出现的次数,i=min,max。
  3. 接着扫描c数组,依次累加前面的值(累加后c[i]表示i在序列中排名的最大下标),从前向后将序列的数填充到r数组(注意取出时要加上min)上。
  4. 此时r数组即为序列排序后的新序列。

具体代码如下:

void CountingSort(int* arr, int len)
{
    int min = arr[0], max = arr[0];
    for (int i = 1; i < len; i++)  // 找出区间上界和下界
    {
        if (arr[i] < min)
            min = arr[i];
        else if (arr[i] > max)
            max = arr[i];
    }

    int* c = new int[max - min + 1]();  // 计数器数组
    for (int i = 0; i < len; i++)
        c[arr[i] - min]++;  // 统计每个元素出现的次数
    for (int i = min + 1; i <= max; i++)
        c[i - min] += c[i - min - 1];  // 将计数器依次累加

    int* r = new int[len]();  // 结果数组
    for (int i = len - 1; i >= 0; i--)
    {
        r[c[arr[i] - min] - 1] = arr[i];  // 放置第 arr[i] 个元素
        c[arr[i] - min]--;  // 更新其对应于计数器的值
    }

    memmove(arr, r, len * sizeof(int));  // 将结果赋值回原数组中
    delete[] c;
    delete[] r;
}

算法示例

示例一

以序列a,b,c排序为例,不妨设序列为3,1,4,0,0,3,4,3。那么首先需要获取序列最小值、最大值、范围。可知最小值为0,最大值为4,范围就是[0, 4),长度为5。

计数数组就是一个长度为5的数组,记录从0到4一共有多少个数字出现(出现个数即计数器值),第一个数字是零,存在的首位就改成0,第二个数字是一个,存在的首位就改成1,第三个数字是四,存在的首位就改成4,以此类推,数字0出现了两次,计数器中将0的数值设为了2,数字1出现了一次,计数器中将1的数值设为了1,数字2没有出现过,所以计数器中的2还是0,数字3出现了3次,计数器中将3的数值设为3,数字4出现了2次,计数器中将4的数值设为2。计数器数组为2,1,0,3,2。
累加数组就是一个长度为5的数组,记录每个值在排序后的序列中应该排在第几位。其实就是一个前缀和。首先将第一个数字计数累加到计数器的第0个数值里,再将第二个数字计数累加到计数器的第一个计数值里,接着是第三个数字,累加到计数器的第四个计数值里,以此类推,最后得到的数组就是0,2,3,6,8。
排序数组就是将原始数组按照累加数组的下标从后向前填值,得到的序列即是排序结束的序列。如果反过来,先放第一个“3”,一共出现3次,那么放到序列中就要从累加数组的最后一位往前放三个“3”,分别加上min,即放在第3位,第4位和第7位。接着放第二个数字0,一共出现了2次,同样也要从累加数组的最后面往前放两个数字0,放在第0位和第1位,以此类推。就得到了排序结果:0,0,1,3,3,3,4,4。

示例二

假设要给字符串进行排序,如“AACCBDEBBECEA”,可以将每个字符的ascii码进行计数排序:

按照字符出现的次数,可以得到计数器数组:

A的ascii码是65出现了2次
B的ascii码是66出现了3次
C的ascii码是67出现了2次
D的ascii码是68出现了1次
E的ascii码是69出现了2次

因为其中的字母序号是连续的,最小的是65,最大的是69,计数数组长度就是69-65+1=5

计数器数组就是长度为5的数组,记录从This is to inform you处于区间[65, 70)内的每一个数字出现次数(出现次数即为计数数组值)。这些数字是65、66、67、68、69,第65个数字出现了两次,计数数组中该数字下标的数值就是2, 第66个数字出现了三次,计数数组中该数字下标的数值就是3,以此类推。

累加数组同样是一个长度为5的数组,记录每个值在排序后的序列中应该排在第几位。计数数组累加后得到的数组为 2 5 7 8 10,比如最小的数字65,他在计数器中对应的下标是0,而且出现2次,因此累加数组的第一个数是2,同样,累加后的数组中的第二个数字是5,累加后的数组中的第一个数是2,所以累加后的数组中的第三个数字的值就是累加数组中的第二个元素加上计数数组中的第三个元素,即5+2=7,以此类推。

排序数组也是将原始数组按照累加数组的下标从后向前填值,即先从后往前扫描一遍计数器中的每个值,再根据该值在累加数组中得到该值在排序数组中的位置,放入该位置即可。

最终结果就是AACCEBBBDEECB。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解计数排序算法原理与使用方法 - Python技术站

(0)
上一篇 2023年3月27日
下一篇 2023年3月27日

相关文章

  • Python数据结构与算法(几种排序)小结

    下面是关于“Python数据结构与算法(几种排序)小结”的完整攻略。 1. 排序算法简介 排序算法是一种将一组数据按照一定规则排列的算法。在计算机科学中,常见的算法包括冒泡排序、选择排序、插入排序、快速排序、归并排序等。 2. Python实现常见排序算法 2.1 冒泡排序 冒泡排序是一种通过交换相邻元素来排序的算法。Python中,我们可以使用以下代码实现…

    python 2023年5月13日
    00
  • python 算法题——快乐数的多种解法

    下面是关于“Python算法题——快乐数的多种解法”的完整攻略。 1. 题目描述 快乐数是指:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,或者是无限循环但始终变不到 1。如果可以变为 1,那么这个数就是快乐数。 例如,19 是一个快乐数,计算过程如下: 1^2 + 9^2 = 828^2 + 2^2 = …

    python 2023年5月13日
    00
  • python机器学习实现oneR算法(以鸢尾data为例)

    下面是详细讲解“Python机器学习实现oneR算法(以鸢尾data为例)”的完整攻略,包括算法原理、Python实现代码和两个示例说明。 算法原理 oneR算法是一种简单的分类算法,它通过统计每个特征的每个取值在不同类别中出现的频率,选择出现频率最高的特征和取值作为分类规则。具体来说,oneR算法的步骤如下: 对于每个特征统计每个取值在不同类别中出现的频率…

    python 2023年5月14日
    00
  • Python语言实现二分法查找

    Python语言实现二分法查找 二分法查找是一种常见的查找算法,它可以在有序数组中快速查找目标元素。本文将介绍如何使用Python语言实现二分法查找。 1. 算法原理 二分法查找的基本思想是:将有序数组分成两部分,取中间元素与目标元素进行比较,相等则返回中间元素的下标,如果目标元素小于中间元素,则在左半部分继续查找,否则在右半部分继续查找,直到找到目标元素或…

    python 2023年5月14日
    00
  • python 实现朴素贝叶斯算法的示例

    下面是详细讲解“Python实现朴素贝叶斯算法的示例”的完整攻略,包括算法原理、Python实现和两个示例说明。 算法原理 朴素贝叶斯算法是一种基于贝叶斯定理和特征条件独立假设的分类算法。其基本思想是根据已知类别的训练数据,计算每个特征在不同类别下的条件概率,然后根据贝叶斯定理计算每个类别的后验概率,最终将样本分配到后验概率最大的类别中。具体来说,朴素贝叶斯…

    python 2023年5月14日
    00
  • 朴素贝叶斯算法的python实现方法

    朴素贝叶斯算法的Python实现方法 朴素贝叶斯算法是一种基于贝叶斯定理的分类算法,它的基本思想是通过计算先验概率和条件概率来确定一个样本属于某个类的概率,从而实现分类。在Python中,可以使用多种库来实现朴素贝叶斯算法,包括scikit-learn、nltk等。本文将详细讲解朴素贝叶斯算法的Python实现方法,包括算法原理、Python实现过程和示例。…

    python 2023年5月13日
    00
  • Python机器学习实战之k-近邻算法的实现

    以下是关于“Python机器学习实战之k-近邻算法的实现”的完整攻略: 简介 k-近邻算法是一种常见的机器学习算法,可以用于分类和回归问题。本教程将介绍如何使用Python实现k-近邻算法,并讨论如何使用该算法进行分类。 步骤 1.导入库和数据 首先,我们需要导入必要的库,包括numpy和matplotlib。在Python中,可以使用以下代码导入这些库: …

    python 2023年5月14日
    00
  • Python 十大经典排序算法实现详解

    下面是关于“Python 十大经典排序算法实现详解”的完整攻略。 1. 十大经典排序算法 排序法是计算机科学中最基本的算法之一,是 Python 开发者必须掌握的算法之一。Python 中常见的算法包括冒泡排序、选择排序、插入排序、快速排序、归并排序、堆排序、计数排序、桶排序、基数排序和鸽巢排序。下将逐一介绍这些算法的实现方法。 1.1 冒泡排序 冒泡排序算…

    python 2023年5月13日
    00
合作推广
合作推广
分享本页
返回顶部