问题在于:
给定一个整数数组,根据元素的频率对数组进行排序。例如,如果输入数组是{2,3,2,4,5,12,2,3,3,3,12},则将数组修改为{3,3,3,3,2,2, 2,12,12,4,5}。如果2个数字具有相同的频率,则打印出第1个数字。
我知道如何部分地做到这一点。这是我的approcach。
我将创建一个类似于:
的结构typedef struct node
{
int index; // for storing the position of the number in the array.
int count; // for storing the number of times the number appears
int value; // for storing the actual value
} a[50];
我将创建这些结构的数组,然后我将根据它们的计数通过排序算法对其进行排序。但是,我如何确保如果两个元素的频率相同,那么该数字应该出现哪个指数值较小?
答案 0 :(得分:1)
#include <stdlib.h> // qsort, malloc, free
#include <stddef.h> // size_t
#include <stdio.h> // printf
struct number
{
const int * value;
int num_occurrences;
};
static void cmp_by_val(const struct number * a, const struct number * b)
{
if (*a->value < *b->value)
return -1;
else if (*b->value < *a->value)
return 1;
else
return 0;
}
static void cmp_by_occurrence_stable(const struct number * a, const struct number * b)
{
if (a->num_occurrences < b->num_occurrences)
return -1;
else if (b->num_occurrences < a->num_occurrences)
return 1;
else if (a->value < b->value)
return -1;
else if (b->value < a->value)
return 1;
else
return 0;
}
static struct number * sort_by_occurrence(const int * arr, size_t N)
{
//
// STEP 1: Convert the input
//
struct number * sort_arr = (struct number *)malloc(N * sizeof(struct number));
if (! sort_arr) return NULL;
for (int k = 0; k < N; ++k)
{
sort_arr[k].value = &arr[k];
sort_arr[k].num_occurrences = 0;
}
//
// STEP 2: Sort the input based on value
//
qsort(sort_arr, N, sizeof(struct number), cmp_by_val);
//
// STEP 3: Count occurrences
//
if (0 < N)
{
int cur_value = *sort_arr[0].value;
int i = 0;
for (j = 1; j < N; ++j)
{
if (*sort_arr[j].value != *sort_arr[i].value)
{
for (int k = i; k < j; ++k)
sort_arr[k].num_occurrences = j - i;
i = j;
}
}
for (; i < N; ++i)
sort_arr[i].num_occurrences = N - i;
}
//
// STEP 4: Sort based on occurrence count
//
qsort(sort_arr, N, sizeof(struct number), cmp_by_occurrence_stable);
//
// DONE
//
return sort_arr;
}
static void print_arr(const struct number * arr, size_t N)
{
if (0 < N)
{
printf("%d", arr[0]->value);
for (int k = 1; k < N; ++k)
printf(", %d", arr[k]->value);
}
printf("\n");
}
int main(int argc, char ** argv)
{
const int EXAMPLE_INPUT[11] = { 2, 3, 2, 4, 5, 12, 2, 3, 3, 3, 12 };
struct number * sort_arr = sort_by_occurrence(EXAMPLE_INPUT, 11);
if (sort_arr)
{
print_arr(sort_arr, 11);
free(sort_arr);
}
};
答案 1 :(得分:0)
似乎问题是在数组元素的频率上使用不稳定排序算法。
再次根据具有相同频率的元素的索引对结果数组执行qsort。
我最小化了代码。遗漏了明显的部分。
struct node
{
int *val;
int freq;
// int index; <- we can do this by comparing &a->val with &b->val
};
int compare_byfreq(const int* a, const int* b)
{
return a->freq - b->freq;
}
int compare_index(const int* a, const int* b)
{
if( a->freq == b->freq)
{
return a->val - b->val; //this can never be zero
}
//else we have different freq don't move elem
return 0;
}
int main()
{
int arr[] = {2, 3, 2, 4, 5, 12, 2, 3, 3, 3, 12};
node *narray = (struct node*)malloc(sizeof(arr) * sizeof(node));
// build the nodes-array
for(int i =0; i < sizeof(arr); i++)
{
/* buid narray here, make sure you store the pointer to val and not the actual values */
}
qsort(narray, sizeof(arr), compare_byfreq);
qsort(narray, sizeof(arr), compare_index);
/*print narray*/
return 0;
}
编辑:@ 0xbe5077ed有一个有趣的想法。而不是比较索引比较您的值的地址! - 我刚刚重新编辑了
的代码答案 2 :(得分:0)
您可以创建一个存储输入数组频率的数组(即frequency [i]是input [i]元素的频率)。之后,很容易订购频率数组(使用稳定的算法)并对输入数组进行相同的更改(交换?)。
为了创建频率数组,你可以使用几种方法,一种简单而低效的方法就是用两个嵌套循环计算每个元素。我为你的想象留下了更有效的替代品。
注意:频率数组与struct节点中的count字段具有相同的功能,但是在单独的内存中。如果您将来不需要频率,我建议您使用分开的内存,因为您可以释放它。
答案 3 :(得分:0)
我现在正在努力学习Java,意识到这可能是一个很好的练习。在Eclipse中尝试并解决了这个问题。 Java很可怕,我回到C解决它,这是一个解决方案,我会在显示后立即解释:
#include <stdio.h>
#include <malloc.h>
typedef struct numbergroup {
int firstencounteridx;
int count;
int thenumber;
} Numbergroup;
int firstoneissuperior( Numbergroup gr1, Numbergroup gr2 ) {
return gr1.count > gr2.count || // don't mind the line-break, it's just to fit
( gr1.count == gr2.count && gr1.firstencounteridx < gr2.firstencounteridx );
}
void sortgroups( Numbergroup groups[], int amount ) {
for ( int i = 1; i < amount; i++ ) {
for ( int j = 0; j < amount - i; j++ ) {
if ( firstoneissuperior( groups[j + 1], groups[j] ) ) {
Numbergroup temp = groups[j + 1];
groups[j + 1] = groups[j];
groups[j] = temp;
}
}
}
}
int main( ) {
int input[] = { 2, 3, 2, 4, 5, 12, 2, 3, 3, 3, 12 };
Numbergroup * groups = NULL;
int amountofgroups = 0;
for ( int i = 0; i < ( sizeof input / sizeof * input ); i++ ) {
int uniqueencounter = 1;
for ( int j = 0; j < amountofgroups; j++ ) {
if ( groups[j].thenumber == input[i] ) {
uniqueencounter = 0;
groups[j].count++;
break;
}
}
if ( uniqueencounter ) {
groups = realloc( groups, ( amountofgroups + 1 ) * sizeof * groups );
groups[amountofgroups].firstencounteridx = i;
groups[amountofgroups].count = 1;
groups[amountofgroups].thenumber = input[i];
amountofgroups++;
}
}
sortgroups( groups, amountofgroups );
for ( int i = 0; i < amountofgroups; i++ )
for ( int j = 0; j < groups[i].count; j++ )
printf( "%d ", groups[i].thenumber );
free( groups );
putchar( 10 );
return 0;
}
首先让我解释一下结构及其功能:它是针对每个唯一的数字。在您的示例中,它适用于2
个,3
个,4
个,5
个和12
个,每个一个,总共5个。每一个都要存储:
例如,对于12
s,它应存储:
firstencounteridx
为5
,即前12 count
为2
thenumber
为12
第一个循环通常会这样做。只要遇到唯一的数字,它就会扩展Numbergroups组,并存储其索引;如果遇到已经有一个组的号码,则增加计数。
然后发出排序,这只是一个冒泡排序。可能与传统的不同,我没有任何记忆。
排序标准函数只是检查第一组的count
字段是否大于另一组;否则它会检查它们是否相同,并且第一组的 firstencounter 早于另一组;在这种情况下,它返回1
为真。这是第一组被认为优于第二组的唯一可行方式。
这是一种方法,可以有其他方法。这只是一个建议,我希望它可以帮助你,不仅仅是为了这个案例,而是一般。
答案 4 :(得分:0)
创建地图并按值对地图进行排序。 O(nlogn)时间和O(n)空间。
import java.util.*;
public class SortByFrequency {
static void sortByFreq( int[] A ) {
// 1. create map<number, its count>
Map<Integer, Integer> map = new HashMap<>();
for(int i = 0; i < A.length; i++) {
int key = A[i];
if( map.containsKey(key) ) {
Integer count = map.get(key);
count++;
map.put(key, count);
}
else {
map.put(key, 1);
}
}
// 2. sort map by value in desc. order
// used modified (for desc. order) MapUtil in http://stackoverflow.com/questions/109383/how-to-sort-a-mapkey-value-on-the-values-in-java
Map<Integer, Integer> map2= MapUtil.sortByValue(map);
for(Map.Entry<Integer, Integer> entry : map2.entrySet() ) {
int num = entry.getKey();
int count = entry.getValue();
for(int i = 0; i < count; i++ ) {
System.out.print( num + " ");
}
}
System.out.println();
}
public static void main(String[] args ) {
int[] A1 = {2, 3, 2, 4, 5, 12, 2, 3, 3, 3, 12};
sortByFreq(A1);
}
}