- 浏览: 202638 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
NIghtmare28:
太好用了, 谢谢
Create Local Cloudera Parcels Repo to Save Your ASS -
oyxccyj:
你好,请问下你如上的问题解决了吗?我现在也遇到同样的问题,网上 ...
Homework - HBase Shell, Java Client and MapReduce Job -
20131007:
用java描述算法?
基础数据结构和算法二:Selection sort -
ender35:
第二种实现仅能用于数组排序
计数排序(Counting Sort) -
fy616508150:
我想知道有括号参加运算怎么办
算24算法实现
计数排序的缺点很明显,需要额外的空间C来作为计数数组,虽然时间复杂度为O(n+k),但当输入序列里元素取值很大的时侯,如k=O(n2),时,此时时间复杂度已经达到n2数量级了,空间的消耗也是让人无法承受的。这里介绍一种另一种线性排序算法——基数排序,可以应对数值很大的情况。
基数排序,即一个数位一个数位地进行排序,平常生活中我们经常使用的一种算法思想:如要对一个日期进行排序,日期中由年、月、日组成的,对于这个问题,我们经常使用的是先比较年份,如果相同再比较月份,如果还相同就比较日。
同理,我们比较一组数,也可以采取这种思想。例如我们使用这种思想对下面四个数进行排序:123、312、245、531,第一次按百位排序:123、245、312、531;第二次按十位排序:312、123、531、245;第三次按个位数排序:531、312、123、245。咦?为什么最后排出来的结果并不是预期的那样?原因是我们从高位开始排序,已经差不多整体有序之后,再到低位时,又全部被打乱了。如果我们之后这样做就不会乱了:高位相同的数,再将它们的低位进行排序….不过这个实现一起比较困难一些。
这里,我们换成从最低有效位到最高有效位进行排序,那么还是上面那个例子:
个位 => 十位 => 百位
531 312 123
312 123 245
123 531 312
245 245 531
可以看到结果正确。通俗地讲,之所以先排低位再排高位,是因为越是后排的数位,其对结果次序的影响越大,很显然是高位比低位对数的大小影响大!
这里再给出一个简单的证明过程:
假定一组序列低t-1位已经排序好了,现在我们按照第t位进行排序。我们只需证明对于任意两个数来说,按照第t位排序之后其相对位置正确。任意两个数这时有两种情况:
1)它们第t位相同,那么此时如果我们保持它们位置的稳定性,那么它们最后仍然有序;
2)它们第t位不同,按照第t位排序之后就有序了。
所以,即证明了基数排序的正确性。从这里我们可以看出非常关键的一点——排序必需要稳定!很快就想到使用前面说过的计数排序算法!
那么可以得出计数排序的伪代码为:
radixSort(A,d) //d为A中元素最多的位数 for i=1 to d do use a stable sort to sort array A on digit i
可以得到时间复杂度为O(d(n+k)); 当d为常数、k=O(n)时,基数排序有线性的运行时间的。
更具体更普遍一点的算法:
/* n为待排序数组A的元素个数,B为按位计数排序后暂存数据的辅助数组,C则是计数数组,b为最大元素的长度(bit位数),r为每个数位的长度(即计数排序以2**r进制) */
radixSort(int A[], int B[], int C[], int n, int b, int r) m=b/r; //m是最大的位数 for i=0 to m-1 do for j=0 to r-1 do C[j] = 0; //计数数组清零 for j=0 to n-1 do C[(A[j]/t)%2**r]++; //C[j]表示等于j的元素个数 for j=1 to r-1 do C[j] = C[j]+C[j-1]; //C[j]表示等于或者小于j的元素个数 for j=n-1 downto 0 do B[--C[(A[j]/t)%2**r]]=A[j]; //计数排序 for j=0 to n-1 do A[j] = B[j]; t = t*2**r;基数排序比较适合对取值很大的数进行排序,也可用来对字符串进行排序。
最终代码如下:(计数排序部分尚未优化)
import java.util.Arrays; /** * @author */ public class RadixSorter { public static boolean USE_LINK = true; /** * * @param keys * @param from * @param len * @param radix * key's radix * @param d * how many sub keys should one key divide to */ public void sort(int[] keys, int from, int len, int radix, int d) { if (USE_LINK) { linkRadixSort(keys, from, len, radix, d); } else { arrayRadixSort(keys, from, len, radix, d); } } private final void arrayRadixSort(int[] keys, int from, int len, int radix, int d) { int[] temporary = new int[len]; int[] count = new int[radix]; int R = 1; for (int i = 0; i < d; i++) { System.arraycopy(keys, from, temporary, 0, len); Arrays.fill(count, 0); for (int k = 0; k < len; k++) { // 当前要排的位 int subkey = (temporary[k] / R) % radix; count[subkey]++; } /* 与计数排序相同 */ for (int j = 1; j < radix; j++) { count[j] += count[j - 1]; } for (int m = len - 1; m >= 0; m--) { int subkey = (temporary[m] / R) % radix; --count[subkey]; // temporary 存储着某位已经排好序的数组 keys[from + count[subkey]] = temporary[m]; } R *= radix; } } private static class LinkQueue { int head = -1; int tail = -1; } private final void linkRadixSort(int[] keys, int from, int len, int radix, int d) { int[] nexts = new int[len]; LinkQueue[] queues = new LinkQueue[radix]; for (int i = 0; i < radix; i++) { queues[i] = new LinkQueue(); } for (int i = 0; i < len - 1; i++) { nexts[i] = i + 1; } nexts[len - 1] = -1; int first = 0; for (int i = 0; i < d; i++) { linkRadixSortDistribute(keys, from, len, radix, i, nexts, queues, first); first = linkRadixSortCollect(keys, from, len, radix, i, nexts, queues); } int[] tmps = new int[len]; int k = 0; while (first != -1) { tmps[k++] = keys[from + first]; first = nexts[first]; } System.arraycopy(tmps, 0, keys, from, len); } private final void linkRadixSortDistribute(int[] keys, int from, int len, int radix, int d, int[] nexts, LinkQueue[] queues, int first) { for (int i = 0; i < radix; i++) { queues[i].head = queues[i].tail = -1; } while (first != -1) { int val = keys[from + first]; for (int j = 0; j < d; j++) { val /= radix; } val = val % radix; if (queues[val].head == -1) { queues[val].head = first; } else { nexts[queues[val].tail] = first; } queues[val].tail = first; first = nexts[first]; } } private int linkRadixSortCollect(int[] keys, int from, int len, int radix, int d, int[] nexts, LinkQueue[] queues) { int first = 0; int last = 0; int fromQueue = 0; for (; (fromQueue < radix - 1) && (queues[fromQueue].head == -1); fromQueue++) { ; } first = queues[fromQueue].head; last = queues[fromQueue].tail; while (fromQueue < radix - 1 && queues[fromQueue].head != -1) { fromQueue += 1; for (; (fromQueue < radix - 1) && (queues[fromQueue].head == -1); fromQueue++) { ; } nexts[last] = queues[fromQueue].head; last = queues[fromQueue].tail; } if (last != -1) { nexts[last] = -1; } return first; } /** * @param args */ public static void main(String[] args) { int[] a = { 1, 4, 8, 3, 2, 9, 5, 0, 7, 6, 9, 10, 9, 135, 14, 15, 11, 222222222, 1111111111, 12, 17, 45, 16 }; USE_LINK = false; RadixSorter sorter = new RadixSorter(); sorter.sort(a, 0, a.length, 10, 10); System.out.println(Arrays.toString(a)); } }
基数排序的缺点:
不呈现时空局部性,因为在按位对每个数进行排序的过程中,一个数的位置可能发生巨大的变化,所以不能充分利用现代机器缓存提供的优势。同时计数排序作为中间稳定排序的话,不具有原地排序的特点,当内存容量比较宝贵的时候,还是有待商榷。
发表评论
-
基础数据结构和算法十四:Directed Graphs
2013-12-15 22:40 1806In directed graphs, edges a ... -
基础数据结构和算法十三:Undirected Graphs (2)
2013-12-13 22:51 1063Design pattern for graph p ... -
基础数据结构和算法十三:Undirected Graphs
2013-12-13 20:15 1204A graph is a set of vertices ... -
基础数据结构和算法十二:Hash table
2013-12-02 22:06 1049Search algorithms that use ... -
基础数据结构和算法十一:Red-black binary search tree
2013-12-01 12:12 1516The insertion algorithm fo ... -
基础数据结构和算法十:2-3 search tree
2013-11-30 11:07 1215Binary search tree works w ... -
基础数据结构和算法九:Binary Search Tree
2013-11-28 22:39 1671A binary search tree (BST) ... -
基础数据结构和算法八:Binary search
2013-11-28 21:21 1142Binary search needs an ordere ... -
基础数据结构和算法七:Priority queue & Heap sort
2013-11-27 19:47 2712Some important applications o ... -
基础算法七: Priority queue & Heap sort
2013-11-26 21:46 0Some important applications ... -
基础数据结构和算法六:Quick sort
2013-11-21 19:33 1237Quick sort is probably used m ... -
Inversions of an array
2013-11-20 22:28 0TODO -
基础数据结构和算法五:Merge sort
2013-11-20 21:44 1993One of mergesort’s most at ... -
基础数据结构和算法四:Shell sort
2013-11-20 19:11 1180Shellsort is a simple exte ... -
Comparing two sorting algorithms
2013-11-19 21:16 843Generally we compare algorith ... -
基础数据结构和算法三:Insertion Sort
2013-11-19 21:06 1000As in selection sort, the ite ... -
基础数据结构和算法二:Selection sort
2013-11-19 20:57 1173One of the simplest sortin ... -
基础数据结构和算法一:UnionFind
2013-11-19 20:47 1278The problem that we consid ... -
Three-sum with linear time complexity
2013-09-14 10:08 0TODO package org.george.algor ... -
Blooming Filter in Hadoop
2013-07-27 22:49 0TODO
相关推荐
排序算法中的基数排序,更重要的是会算时间复杂度,基数排序可以说是以计数排序位基础的,只不过变成了一位一位来或者一个字节一个字节来,每位或者每个字节都过了一遍,则排序完毕。很简单的程序,在code::block IDE...
Java基数排序Radix Sort原理及用法解析 Java基数排序Radix Sort是一种高效的稳定性排序算法, thuộc於“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort。顾名思义,它是通过键值的...
经典排序算法 – 基数排序Radix sort 原理类似桶排序,这里总是需要10个桶,多次使用 首先以个位数的值进行装桶,即个位数为1则放入1号桶,为9则放入9号桶,暂时忽视十位数 例如 待排序数组[62,14,59,88,16]简单点五个...
基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。这种排序方法对于大数据量的处理非常有效,尤其适合于数据范围远大于内存大小的情况。以下是基数排序的详细...
void radix_sort(int A[],int B[],int length,int d) { int i; for (i=1;i;i++) { get_k(A,B,i,length,d); insert_sort(B,A,length); printf("\n\n第%d位排序完成的结果:\n\n",i); print_A(A,length); ...
基数排序:基数排序(Radix Sort)是一种非比较型的整数排序算法,其基本思想是按照从最低位到最高位的顺序对数字进行排序。基数排序可以用于对整数或字符串进行排序,因为它实际上是对每个数字位进行排序,而不是...
### Radix Sort (基数排序) 排序算法详解 #### 一、算法介绍与应用场景 基数排序(Radix Sort)是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达...
基数排序(Radix Sort)是一种非比较型整数排序算法,其效率高于基于比较的传统排序算法。本文将深入探讨基数排序的基本原理及其程序实现。 #### 基数排序概述 基数排序通过按位对整数进行排序来工作。它首先按照...
经典排序算法 - 基数排序Radix sort 经典排序算法 - 鸽巢排序Pigeonhole sort 经典排序算法 - 归并排序Merge sort 经典排序算法 - 冒泡排序Bubble sort 经典排序算法 - 选择排序Selection sort 经典排序算法 - ...
基数排序是一种非比较排序算法,其基本思想是将整数按位数切割成不同的数字,然后按每个位数分别进行排序。
基数排序(Radix Sort)是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别进行排序。以下是对基数排序原理及应用的详细解释: 基数排序的原理 1. 数位排序:基数排序从最低位...
基数排序(radix sort)又称桶排序(bucket sort),相对于常见的比较排序,基数排序是一种分配式排序,需要将关键字拆分成数字位。并且按照数字位的值对数据项进行排序,这种方法不需要进行比较操作。 为了尽可能少的...
**基数排序(Radix Sort)**是一种非比较型整数排序算法,它的原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。这种算法对于大数据量的排序非常有效,尤其是在数据范围较大的情况下,其时间复杂度可以...
在`基数排序Radix_sort.cpp`中,我们可以看到如何利用这个原理实现排序过程。 其次,堆排序是一种基于比较的排序算法,它通过构建一个大顶堆或小顶堆来完成排序。堆是一种特殊的树形数据结构,其每个父节点的值都...
基数排序(Radix Sort)是一种非比较型的整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表示字符串、卡片等数据(当成是整数即可),所以基数排序并不限于整数。它是...
1. 计数排序(Counting Sort)基数排序: 计数排序本身是一种非比较型排序,适用于排序非负整数。在基数排序中,我们从最低有效位(个位)开始,到最高有效位(高位)结束。对于每一位,我们创建一个大小为10的数组...
基数排序(Radix Sort)是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表示字符串(如将数字转换为字符串形式),所以基数排序也可以很自然地扩展到...