基数排序vs计数排序vs桶排序。有什么不同?

浏览:64日期:2024-02-17
如何解决基数排序vs计数排序vs桶排序。有什么不同??

让我们从用C重写代码开始,因为C对我来说比较熟悉。因此,让我们用一些注释来调用代码:

intcounting_sort(int a[], int a_len, int maxVal){ int i, j, outPos = 0; int bucket_len = maxVal+1; int bucket[bucket_len]; /* simple bucket structure */ memset(bucket, 0, sizeof(int) * bucket_len); /* one loop bucket processing */ for (i = 0; i < a_len; i++) { bucket[a[i]]++; /* simple work with buckets */ } for (i=0; i < bucket_len; i++) { for (j = 0; j < bucket[i]; j++){ a[outPos++] = i;} } return 0;}

现在让我们提供一些实际数据:

[126、348、343、432、316、171、556、223、670、201]

在输出上,我们有

[126、171、201、223、316、343、348、432、556、670]

看来一切还好吗?还没。让我们看一下maxVal。它是670(!)。这里要排序10个元素的数组,我们使用了670个元素的数组,主要是零。非常。为了解决计数排序的问题,我们有两种可能的归纳方法:

1)第一种方式-以数字方式进行排序。这称为基数排序。让我们显示一些代码,尝试使其尽可能接近计数排序代码。再看一下评论:

intradix_sort(int a[], int a_len, int ndigits){ int i; int b[a_len]; int expn = 1; /* additional loop for digits */ for (i = 0; i != ndigits; ++i) { int j; int bucket[10] = {0}; /* still simple buckets */ /* bucket processing becomes tricky */ for (j = 0; j != a_len; ++j)bucket[ a[j] / expn % 10 ]++; for (j = 1; j != 10; ++j)bucket[j] += bucket[j - 1]; for (j = a_len - 1; j >= 0; --j)b[--bucket[a[j] / expn % 10]] = a[j]; for (j = 0; j != a_len; ++j)a[j] = b[j]; expn *= 10; }}

我们正在乘以N附近的内存。利润?也许。但是在某些情况下,接近N的倍数非常重要。程序,一天工作和一周工作与用户视图有很大不同,即使两者都分别工作为1 *O(N)和7 * O(N)。因此,我们要进行第二种概括:

2)第二种方法-使水桶更加精致。这称为存储桶排序。

让我们再次从一些代码开始。在进行哲学争论之前,我更喜欢使用更多代码。仍然看评论,它们是必不可少的。

intbucket_sort(int a[], int a_len, int maxVal){ int i, aidx; typedef struct tag_list { int elem; struct tag_list *next; } list_t, *list_p; list_p bucket[10] = {0}; /* sophisticated buckets */ /* one loop simple processing with one more inner loop to get sorted buckets (insert-sort on lists, Cormen-style) */ for (i = 0; i != a_len; ++i) { int bnum = (10 * a[i]) / maxVal; list_p bptr = bucket[bnum]; list_p belem = malloc(sizeof(list_t)); belem->elem = a[i]; if (bptr == 0){ bucket[bnum] = belem; belem->next = 0; continue;} else if (a[i] <= bptr->elem){ belem->next = bptr; bucket[bnum] = belem; continue;} else{ while (bptr != 0) { if ((bptr->elem <= a[i]) && ((bptr->next == 0) || (bptr->next->elem > a[i]))){ belem->next = bptr->next; bptr->next = belem; break;} bptr = bptr->next; } } } /* one loop (looks as two) to get all back */ aidx = 0; for (i = 0; i != 10; ++i) { list_p bptr = bucket[i]; while (bptr){ list_p optr = bptr; a[aidx] = bptr->elem; aidx += 1; bptr = bptr->next; free(optr);} } return 0;}

那我们这里有什么?我们正在交易一些复杂的存储桶结构,并要求动态分配内存,但要赢得静态内存,并且乘数平均接近N。

现在,让我们回想一下我们在代码中看到的内容:

计数排序-简单的存储桶,简单的处理,内存开销基数排序-简单的存储桶,复杂的处理,速度开销(仍然需要额外的静态内存)桶分类-复杂的桶,简单的处理,需要动态内存,平均水平很好

基数和存储桶排序因此是计数排序的两个有用的概括。它们在计数排序和彼此计数方面有很多共同点,但是在每种情况下,我们都会输掉某些东西而赢得一些东西。软件工程是这些机会之间的平衡。

解决方法

我正在阅读基数,计数和存储桶排序的定义,似乎所有这些都只是下面的代码:

public static void sort(int[] a,int maxVal){ int [] bucket=new int[maxVal+1]; for (int i=0; i<bucket.length; i++){bucket[i]=0; } for (int i=0; i<a.length; i++){bucket[a[i]]++; } int outPos=0; for (int i=0; i<bucket.length; i++){for (int j=0; j<bucket[i]; j++){ a[outPos++]=i;} }}

我知道我做错了,所以我想念什么?如果您认为可以帮助用Java或C进行解释,请显示代码。

相关文章: