12

Mi chiedo quale sia l'approccio migliore per questo calcolo. Supponiamo di avere una matrice di input di valori e una matrice di limiti: volevo calcolare/benizzare la distribuzione di frequenza per ciascun segmento nell'array di limiti.Qual è il modo più veloce per calcolare la distribuzione di frequenza per array in C#?

È consigliabile utilizzare la ricerca del bucket per quello?

In realtà ho trovato questa domanda Calculating frequency distribution of a collection with .Net/C#

Ma io non capisco come utilizzare benne a tal fine causano la dimensione di ciascun benna può essere diversa nella mia situazione.

EDIT: Dopo tutte le discussioni ho una soluzione di loop interno/esterno, ma comunque voglio eliminare il ciclo interno con un dizionario per ottenere prestazioni O (n) in quel caso, se ho capito correttamente ho bisogno di hash input valori in un indice bucket. Quindi abbiamo bisogno di una sorta di funzione di hash con complessità O (1)? Qualche idea su come farlo?

+1

Può descrivere la matrice confini un po 'meglio? Esiste una relazione tra i vari limiti (cioè sono sequenziali) o sono completamente casuali in termini di dimensioni e "posizione"? Presumo che la matrice dei limiti copra completamente la gamma di valori possibili - è vero? Inoltre, suppongo che non ci siano sovrapposizioni - giusto? –

+0

più veloce nel significato della grande "O" o nel significato di piccolo codice? Un approccio semplice potrebbe essere quello di scrivere una funzione Func e utilizzarla con Linqs .GroupBy per raggrupparlo in "Secchi", ma potrebbero esserci modi di calcolo più veloci per farlo. – Carsten

+0

Sì, hai ragione. I valori al contorno stanno aumentando monotonicamente in valore. Non sono sovrapposizioni e coprono la gamma di valori possibili. Quindi, ad esempio: 0, 10, 50, 100, 120. – Andrey

risposta

4

L'ordinamento con benna è già O (n^2) nel caso peggiore, quindi farei semplicemente un semplice ciclo interno/esterno qui. Dato che il tuo bucket array è necessariamente più corto del tuo array di input, tienilo sul loop interno. Dal momento che stai utilizzando dimensioni personalizzate del bucket, non ci sono davvero trucchi matematici che possano eliminare quel loop interno.

int[] freq = new int[buckets.length - 1]; 
foreach(int d in input) 
{ 
    for(int i = 0; i < buckets.length - 1; i++) 
    { 
     if(d >= buckets[i] && d < buckets[i+1]) 
     { 
      freq[i]++; 
      break; 
     } 
    } 
} 

È anche O (n^2) il caso peggiore ma non si può battere la semplicità del codice. Non mi preoccuperei dell'ottimizzazione finché non diventerà un vero problema. Se si dispone di un array bucket più grande, è possibile utilizzare una ricerca binaria di qualche tipo. Ma, dato che le distribuzioni di frequenza sono tipicamente di < 100 elementi, dubito che vedresti un sacco di vantaggi in termini di prestazioni nel mondo reale.

+1

Cosa ne pensi dell'applicazione di BucketizedHashtable come se fosse presentata in Java? O per quanto riguarda l'ordinamento dell'array all'inizio dell'esecuzione, ha senso? –

+0

Elimina il ciclo interno con un 'Dictionary ' per ottenere O (n) perf ammortizzato. –

+0

@Hans Cosa intendi? Io non capisco :( – Andrey

1

Se la matrice di ingresso rappresenta i dati del mondo reale (con i suoi modelli) e la matrice dei confini è grande per scorrere di nuovo e di nuovo nel ciclo interno si può considerare il seguente approccio:

  • Prima di ogni sorta il tuo array di input. Se lavori con i dati del mondo reale , ti consiglio di considerare Timsort - Wiki per questo. Lo standard offre ottime garanzie di prestazioni per i modelli che possono essere visualizzati nei dati reali .

  • Traverse mediante array filtrate e confrontarlo con il primo valore nella matrice dei confini:

    • Se valore nella matrice di ingresso è inferiore a confine - contatore di frequenza di incremento per questo confine
    • Se valore l'array di input è più grande del limite - passa al valore successivo in una matrice di limiti e incrementa il contatore per il nuovo limite.

In un codice che può assomigliare a questo:

Timsort(myArray); 
int boundPos; 
boundaries = GetBoundaries(); //assume the boundaries is a Dictionary<int,int>() 

for (int i = 0; i<myArray.Lenght; i++) { 
    if (myArray[i]<boundaries[boundPos]) { 
    boundaries[boubdPos]++; 
    } 
    else { 
    boundPos++; 
    boundaries[boubdPos]++; 
    } 
} 
+1

sono rappresentati con una matrice di valori. ma per quanto riguarda la complessità? come ho capito per Timsort nel caso peggiore O (nlogn) + O (n) per il ciclo. Penso che il ciclo interno/esterno con la ricerca binaria dovrebbe essere migliore? – Andrey

+2

Non proprio giusto. Questo fallirà se c'è un secchio "vuoto" nel mezzo. Cioè, ci sono due valori di input nell'array ordinato che sono uno accanto all'altro, ma vanno in bucket che non sono uno accanto all'altro. Ma ciò può essere risolto. Tutto sommato, questa è un'ottima idea. A seconda dei dati, potrebbe anche essere possibile utilizzare Radix Sort, che è O (n), anche se potrebbe richiedere un sacco di dati per renderlo utile. Ma il tempo di esecuzione complessivo sarebbe un pulito O (n). –

+0

P.S. Ci scusiamo per aver postato questo testo come risposta. Doveva essere un commento. –

Problemi correlati