Comme personne ne semble l'avoir fait auparavant, j'ai pensé que ce serait une bonne idée de l'avoir comme référence quelque part. J'ai cherché à caractériser l'architecture de l'ordinateur par le biais d'un benchmark ou d'un code-skimming. array_*
fonctions. J'ai essayé de placer les Big-O les plus intéressants en tête de liste. Cette liste n'est pas complète.
Note : Tous les Big-O ont été calculés en supposant qu'une consultation de hachage est O(1) même si c'est en réalité O(n). Le coefficient de n est si faible que la surcharge en mémoire vive liée au stockage d'un tableau suffisamment grand vous ferait souffrir avant que les caractéristiques du Big-O de la recherche ne commencent à prendre effet. Par exemple, la différence entre un appel à array_key_exists
à N=1 et N=1.000.000 est une augmentation de temps de ~50%.
Points intéressants :
-
isset
/ array_key_exists
est beaucoup plus rapide que in_array
et array_search
-
+
(union) est un peu plus rapide que array_merge
(et il est plus beau). Mais le fonctionnement est différent, alors gardez cela à l'esprit.
-
shuffle
est sur le même palier Big-O que array_rand
-
array_pop
/ array_push
est plus rapide que array_shift
/ array_unshift
en raison de la pénalité de réindexation
Recherches :
array_key_exists
O(n) mais vraiment proche de O(1) - c'est à cause de la scrutation linéaire dans les collisions, mais comme la chance de collisions est très petite, le coefficient est aussi très petit. Je trouve que vous traitez les recherches de hachage comme O(1) pour donner un big-O plus réaliste. Par exemple, la différence entre N=1000 et N=100000 n'est qu'un ralentissement d'environ 50%.
isset( $array[$index] )
O(n) mais très proche de O(1) - il utilise la même recherche que array_key_exists. Puisqu'il s'agit d'une construction du langage, la recherche sera mise en cache si la clé est codée en dur, ce qui permet d'accélérer les cas où la même clé est utilisée de manière répétée.
in_array
O(n) - c'est parce qu'il effectue une recherche linéaire dans le tableau jusqu'à ce qu'il trouve la valeur.
array_search
O(n) - il utilise la même fonction centrale que in_array mais renvoie une valeur.
Fonctions de file d'attente :
array_push
O(∑ var_i, pour tout i)
array_pop
O(1)
array_shift
O(n) - il doit réindexer toutes les clés
array_unshift
O(n + ∑ var_i, pour tous les i) - il faut réindexer toutes les clés.
Intersection, union, soustraction de tableaux :
array_intersect_key
si intersection 100% faire O(Max(param_i_size)*∑param_i_count, pour tous les i), si intersection 0% faire O(∑param_i_size, pour tous les i)
array_intersect
si intersection 100% faire O(n^2*∑param_i_count, pour tout i), si intersection 0% faire O(n^2)
array_intersect_assoc
si intersection 100% faire O(Max(param_i_size)*∑param_i_count, pour tous les i), si intersection 0% faire O(∑param_i_size, pour tous les i)
array_diff
O(π param_i_size, pour tout i) - C'est le produit de tous les param_size
array_diff_key
O(∑ param_i_size, pour i != 1) - c'est parce que nous n'avons pas besoin d'itérer sur le premier tableau.
array_merge
O( ∑ array_i, i != 1 ) - n'a pas besoin d'itérer sur le premier tableau.
+
(union) O(n), où n est la taille du second tableau (c'est-à-dire tableau_premier + tableau_second) - moins de surcharge que array_merge puisqu'il n'a pas à renuméroter.
array_replace
O( ∑ array_i, pour tous les i )
Random :
shuffle
O(n)
array_rand
O(n) - Nécessite un sondage linéaire.
Big-O évident :
array_fill
O(n)
array_fill_keys
O(n)
range
O(n)
array_splice
O(décalage + longueur)
array_slice
O(offset + longueur) ou O(n) si longueur = NULL
array_keys
O(n)
array_values
O(n)
array_reverse
O(n)
array_pad
O(taille_du_papier)
array_flip
O(n)
array_sum
O(n)
array_product
O(n)
array_reduce
O(n)
array_filter
O(n)
array_map
O(n)
array_chunk
O(n)
array_combine
O(n)
Je tiens à remercier Eureqa pour avoir facilité la recherche du Big-O des fonctions. C'est un incroyable gratuit qui peut trouver la meilleure fonction d'ajustement pour des données arbitraires.
EDIT :
Pour ceux qui doutent que les recherches dans les tableaux PHP sont O(N)
J'ai écrit un benchmark pour tester cela (ils sont toujours efficaces). O(1)
pour les valeurs les plus réalistes).
$tests = 1000000;
$max = 5000001;
for( $i = 1; $i <= $max; $i += 10000 ) {
//create lookup array
$array = array_fill( 0, $i, NULL );
//build test indexes
$test_indexes = array();
for( $j = 0; $j < $tests; $j++ ) {
$test_indexes[] = rand( 0, $i-1 );
}
//benchmark array lookups
$start = microtime( TRUE );
foreach( $test_indexes as $test_index ) {
$value = $array[ $test_index ];
unset( $value );
}
$stop = microtime( TRUE );
unset( $array, $test_indexes, $test_index );
printf( "%d,%1.15f\n", $i, $stop - $start ); //time per 1mil lookups
unset( $stop, $start );
}