Comment puis-je trier les nombres lexicographiquement?
Voici le scénario.
Je me suis donné un tableau 'A' des nombres entiers. La taille du tableau n'est pas fixe. La fonction que je suis censé écrire peut être appelé qu'une seule fois avec un tableau de quelques nombres entiers tandis que l'autre fois, elle peut même contenir des milliers de nombres entiers. En outre, chaque entier n'a pas besoin de contenir le même nombre de chiffres.
Je suis censé pour "trier" les chiffres dans le tableau de telle sorte que la matrice résultante a les entiers ordonnés dans une lexicographique (j'.e ils sont triés en fonction de leurs représentations de chaîne. Ici, "123" est la représentation de chaîne d'123). Veuillez noter que la sortie doit contenir des entiers, pas de leur chaîne équivalents.
Par exemple: si l'entrée est:
[ 12 | 2434 | 23 | 1 | 654 | 222 | 56 | 100000 ]
Le résultat doit être:
[ 1 | 100000 | 12 | 222 | 23 | 2434 | 56 | 654 ]
Mon approche initiale: je me suis converti chaque entier à son format de chaîne de caractères, puis ajouter des zéros à son droit de faire tous les entiers contiennent le même nombre de chiffres (ce qui était le sale l'étape, car elle porte sur le suivi etc rendant la solution très inefficace) et puis ne radix de tri.
Enfin, j'ai enlevé le collier de zéros, convertis les chaînes de retour à leur entiers et les mettre dans le tableau résultant. C'était une solution inefficace.
J'ai été amené à croire que la solution n'a pas besoin de rembourrage, etc et il y a une solution simple où vous avez juste à traiter les nombres d'une certaine façon (un peu?) pour obtenir le résultat.
Qu'est-ce que l'espace-sage, la solution la plus efficiente que vous pouvez penser? Avec le temps?
Si vous donnez le code, je préfère Java ou en pseudo-code. Mais si cela ne vous convient pas, toute langue doit être fine.
source d'informationauteur Skylark
Vous devez vous connecter pour publier un commentaire.
Exécutable pseudo-code (aka Python):
thenumbers.sort(key=str)
. Ouais, je sais que l'utilisation de Python est un peu comme de la triche, c'est juste trop puissant;-). Mais sérieusement, cela veut dire aussi: si vous pouvez trier un tableau de chaînes de caractères de manière lexicographique, comme Python est en quelque sorte intrinsèquement peut, alors il suffit de faire la "clé de chaîne" à la sortie de chaque numéro et de tri auxiliaire array (vous pouvez alors reconstituer les numéros souhaités tableau par un str->int transformation, ou en faisant le tri sur les indices par indirection, etc etc); ceci est connu comme UAD (Décorer, de Tri, Undecorate) et c'est ce que lekey=
argument de Python est une sorte d'outils.Plus en détail (pseudo-code):
aux
tant que lenumbers
tableaulength of numbers-1
aux[i]=stringify(numbers[i])
indices
de la même longueurlength of numbers-1
indices[i]=i
indices
en utilisant commecmp(i,j)
strcmp(aux[i],aux[j])
results
de la même longueurlength of numbers-1
results[i]=numbers[indices[i]]
results
surnumbers
aux[i]
et aussiaux
indices
results
Puisque vous avez mentionné Java est la langue en question:
Vous n'avez pas besoin de convertir des chaînes de caractères. Au lieu de cela, définir votre propre comparaison et de l'utiliser que dans le tri.
Spécifiquement:
Ensuite, vous pouvez trier le tableau comme ceci:
(Note: Le
int
/Integer
incompatibilité fonctionne automatiquement par le biais de l'auto-boxing)Je venais de les transformer en des chaînes, puis les trier puis de les trier à l'aide de strcmp, qui ne lex comparaisons.
Alternativement, vous pouvez écrire un "lexcmp" fonction qui compare deux nombres à l'aide de % à 10 et de 10, mais c'est en gros la même chose que l'appel à la atoi de nombreuses fois, pas une bonne idée.
Le tri réelle peut être fait par n'importe quel algorithme vous le souhaitez. La clé de ce problème est de trouver la fonction de comparaison qui permettra de les identifier correctement les nombres qui doivent être "moins que" d'autres, selon ce schéma:
Ma tentation serait de dire que l'int de conversion de chaîne de caractères qui se passerait dans le comparitor code plutôt qu'en vrac. Même si cela peut être plus élégant à partir d'un code-point de vue, je dirais que l'exécution de l'effort serait plus grande que chaque nombre peut être comparé plusieurs fois.
Je serais enclin à créer un nouveau tableau contenant à la fois l'int et la représentation sous forme de chaîne (pas sûr que vous devez compléter la chaîne des versions pour la comparaison de chaînes à produire l'ordre que vous avez donné), de sorte que sur la chaîne, puis de copier l'int les valeurs du tableau original.
Je ne peux pas penser à une smart mathématiquement de trier ce que par votre propre déclaration que vous voulez trier lexicographiquement si vous avez besoin de transformer les numéros de cordes pour le faire.
Vous avez certainement n'avez pas besoin de pad le résultat. Il ne changera pas l'ordre de la lexicographiques comparer, ça va être plus enclins à faire des erreurs, et il va juste perdre cycles PROCESSEUR. La plupart des espaces "sage" méthode efficace serait de convertir les numéros de cordes quand ils sont comparés. De cette façon, vous n'auriez pas besoin d'allouer un supplément de tableau, les chiffres seront comparés en place.
Vous pouvez obtenir une assez bonne mise en œuvre rapidement par juste les convertir en chaînes en tant que de besoin. Stringifying un nombre n'est pas particulièrement cher et, puisque vous êtes seulement à faire avec deux cordes à la fois, il est tout à fait probable qu'ils restent dans le cache du PROCESSEUR en tout temps. Donc, la comparaison sera beaucoup plus rapide que dans le cas où vous convertir l'ensemble de la matrice de chaînes de caractères, car ils n'auront pas besoin d'être chargé dans la mémoire principale dans le cache. Les gens ont tendance à oublier qu'un CPU a un cache, et que les algorithmes qui font bien leur travail dans une petite zone de la mémoire profiteront grandement de la beaucoup plus rapide d'accès au cache. Sur certaines architectures, le cache est plus rapide que la mémoire que vous pouvez faire des centaines d'opérations sur vos données dans le temps, il aurait pris de le charger à partir de la mémoire principale. Donc, faire plus de travail dans la fonction de comparaison pourrait en fait être beaucoup plus rapide que le pré-traitement de la matrice. Surtout si vous avez un grand tableau.
Essayez de faire la chaîne de la sérialisation et la comparaison à un traitement de référence de la fonction et de la valeur de référence. Je pense que ça va être une très bonne solution. Exemple java-ish pseudo-code:
Je pense que toute fantaisie peu sage comparaisons que vous pourriez faire devrait être d'environ équivalent au travail impliqués dans la conversion de nombres en chaînes. De sorte que vous ne serait probablement pas obtenir des avantages importants. Vous ne pouvez pas simplement faire un direct bit à bit de comparaison, qui vous donnent un ordre différent de l'ordre lexicographique de tri. Vous aurez besoin pour être en mesure de comprendre chacun des chiffres pour le numéro de toute façon, de sorte qu'il est plus simple de juste faire des cordes. Il y a peut être certains de la nappe de truc, mais chaque avenue, je peux penser à du haut de ma tête est délicat, source d'erreurs, et beaucoup plus de travail que ce qu'il vaut.
Pseudocode:
Alors, quelles sont
munge
etunmunge
?munge
est différent en fonction de l'entier de la taille. Par exemple:Esentially ce munge est en train de faire est de dire ce que l'ordre de 4 bits entiers quand triés lexigraphically. Je suis sûr que vous pouvez voir qu'il y a un modèle ici --- je ne pas avoir à utiliser un commutateur --- et que vous pouvez écrire une version de
munge
qui gère 32 bits entiers raisonnablement facilement. Pensez à comment vous l'écrire versions demunge
pour 5, 6 et 7 bits entiers si vous ne pouvez pas voir immédiatement le motif.unmunge
est l'inverse demunge
.De sorte que vous pouvez éviter de convertir quelque chose à une chaîne --- vous n'avez pas besoin de la mémoire supplémentaire.
Si vous voulez essayer une meilleure prétraiter-tri-post-traitement, puis notez qu'un int est d'au plus 10 chiffres décimaux (en ignorant signé-ness pour le moment).
De sorte que le binaire codé décimal de données pour qu'il s'adapte en 64 bits. Carte chiffres 0->1, 1->2, etc, et utiliser 0 comme un NUL de terminaison (pour s'assurer que le "1" qui vient de sortir moins de "10"). Maj de chaque chiffre, à son tour, en commençant par le plus petit, en haut d'une longue. Trier les aspire, qui sortira le vocabulaire de la commande à l'origine pour les services de renseignements. Puis le reconvertir en déplaçant les chiffres un à un temps de retour sur le haut de chaque long:
Ou quelque chose comme ça. Depuis Java n'a pas non signé ints, vous auriez à le modifier un peu. Il utilise beaucoup de mémoire de travail (deux fois la taille de l'entrée), mais c'est toujours moins que votre approche initiale. Il pourrait être plus rapide que la conversion de chaînes à la volée dans la comparaison, mais il utilise plus de mémoire pic. En fonction de la GC, il pourrait le taux de désabonnement son chemin à travers de moins de mémoire totale, cependant, et nécessitent moins de collection.
Si tous les nombres sont à moins de 1E+de 18 ans, vous pourriez lancer chaque numéro de UINT64, de multiplier par dix et en ajouter un, et ensuite de multiplier par dix jusqu'à ce qu'ils sont au moins 1E+19. Faire le tri de ceux-ci. Pour récupérer les numéros d'origine, diviser chaque nombre par dix jusqu'à ce que le dernier chiffre non nul (il devrait être l'un) et ensuite de diviser par dix, une fois de plus.
La question n'indique pas comment traiter les entiers négatifs dans le lexicographique ordre de classement des caractères. La chaîne basée sur des méthodes présentées précédemment généralement trier les valeurs négatives à l'avant; par exemple, { -123, -345, 0, 234, 78 } serait laissé dans cet ordre. Mais si le signe moins, étaient censés être ignoré, l'ordre de sortie doit être { 0, -123, 234, -345, 78 }. On pourrait adapter une chaîne de caractères-méthode basée sur la production de cette commande par un peu lourd des tests supplémentaires.
Il peut être plus simple, en théorie et en code, d'utiliser un comparateur qui compare les fractions de communes des logarithmes de deux nombres entiers. C'est, il permettra de comparer les mantissas de la base 10 logarithmes des deux nombres. Un logarithme à base comparateur de courir plus vite ou plus lentement que d'une chaîne de base de comparaison, selon un PROCESSEUR à virgule flottante spécifications de performance et sur la qualité des implémentations.
Le code java à la fin de cette réponse comprend deux logarithme à base de comparateurs:
alogCompare
etslogCompare
. L'ancien ignore les signes, afin d'éviter de produire { 0, -123, 234, -345, 78 } à partir de { -123, -345, 0, 234, 78 }.Le nombre de groupes sont indiqués à côté de la sortie produite par le programme java.
Le “dar rand” montre un hasard-tableau de données
dar
généré. Il lit ensuite vers le bas, 5 éléments par ligne. Remarque, les tableauxsar
lara
etlars
à l'origine sont des ménagères de copies dedar
.Le “dar tri” est
dar
après le tri parArrays.sort(dar);
.Le “sar lex” montre tableau
sar
après le tri avecArrays.sort(sar,lexCompare);
oùlexCompare
est similaire à laComparator
montré dans Jason Cohen réponse.La “lar s journal” montre tableau
lars
après le tri parArrays.sort(lars,slogCompare);
illustrant un logarithme à base de la méthode qui donne le même ordre que nelexCompare
et d'autres de la chaîne des méthodes basées sur.La “lar un journal de la section” tableau montre
lara
après le tri parArrays.sort(lara,alogCompare);
illustrant un logarithme à base de méthode qui ignore les signes moins.Code Java est indiqué ci-dessous.
Si vous allez pour l'espace-sage de l'efficacité, j'essaierais juste de faire le travail dans la fonction de comparaison de la sorte
Si il est trop lent (c'est plus lent que le prétraitement, bien sûr), de suivre les conversions de quelque sorte que la fonction de comparaison ne tient pas avoir à le faire.
Optimisation Possible: au Lieu de ceci:
vous pouvez multiplier chaque nombre par (10^N - log10(nombre)), N étant un nombre plus grand que log10 de l'un de vos numéros.
Certains timings ... tout d'Abord, avec vide @x:
Maintenant, avec 10 000 généré de façon aléatoire des éléments:
Cela inclut le temps nécessaire pour générer les 10 000 éléments, mais pas le temps de leur sortie de la console. La sortie ajoute une seconde environ.
Ainsi, économiser le temps du programmeur 😉
Vraiment hacky méthode (à l'aide de C) serait:
En Java (à partir de ici):
de sorte que vous vous trier sur le long
mantissa
ici.