J'ai besoin de trier les grands nombres stockés sous forme de chaîne dans un tableau de chaînes, mais mon algorithme et la méthode de tri Array construite .net ne fonctionnent pas.
J'ai essayé de convertir le nombre en long ou ulong mais cela jette une exception de débordement.
Voici le code que j'ai essayé:
Array.Sort(unsorted);
Également utilisé la méthode suivante :
string[] unsorted = { "1","2","100","12303479849857341718340192371",
"3084193741082937","3084193741082938","111","200" };
for (int index = 0; index < unsorted.Length - 1; index++)
{
for (int count = 0; count < unsorted.Length - index - 1; count++)
{
if (string.Compare(unsorted[count], unsorted[count + 1]) == 1)
{
string temp = unsorted[count];
unsorted[count] = unsorted[count + 1];
unsorted[count + 1] = temp;
}
}
}
Le tableau doit être trié correctement.
9 Réponses :
Vous n'avez pas de tableau de nombres, vous avez un tableau de chaînes. Ils sont donc triés par ordre alphanumérique.
Une option serait d'utiliser la classe BigInteger pour les stocker sous forme de nombres:
string[] unsorted = {
"00000000000000000000000000001",
"00000000000000000000000000002",
"00000000000000000000000000100",
"12303479849857341718340192371",
"00000000000003084193741082937",
"00000000000003084193741082938",
"00000000000000000000000000111",
"00000000000000000000000000200"
};
À défaut, si vous souhaitez les conserver comme les chaînes, vous pouvez les compléter avec des zéros pour rendre les longueurs cohérentes afin que le tri alphanumérique fonctionne:
BigInteger[] unsorted = {
BigInteger.Parse("1"),
BigInteger.Parse("2"),
BigInteger.Parse("100"),
BigInteger.Parse("12303479849857341718340192371"),
BigInteger.Parse("3084193741082937"),
BigInteger.Parse("3084193741082938"),
BigInteger.Parse("111"),
BigInteger.Parse("200")
};
Si vous choisissez le premier, changez simplement les types dans votre si bloque également BigInteger .
L'op veut trier en utilisant des chaînes pas Big Int. Le tri des chaînes est simple en utilisant ma solution et s'exécutera plus rapidement que la conversion en gros int.
Essayez de suivre:
string[] unsorted = { "1","2","100","12303479849857341718340192371",
"3084193741082937","3084193741082938","111","200" };
var groups = unsorted.OrderBy(x => x.Length).GroupBy(x => x.Length).ToArray();
List<string> results = new List<string>();
foreach (var group in groups)
{
string[] numbers = group.ToArray();
for(int i = 0; i < numbers.Count() - 1; i++)
{
for(int j = i + 1; j < numbers.Count(); j++)
{
if(numbers[i].CompareTo(numbers[j]) == 1)
{
string temp = numbers[i];
numbers[i] = numbers[j];
numbers[j] = temp;
}
}
}
results.AddRange(numbers);
}
J'ai résolu le problème. J'ai vu une erreur après avoir posté.
Ce ne sera pas robuste si certaines chaînes ont des zéros au début. Ce n'est cependant pas nécessairement une exigence.
cela a n ^ 3 complexité, par le je dois utiliser le tri à bulles
Ce n'est pas n ^ 3. Il est inférieur à 2 * (n ^ 2). Vous devez d'abord trier par la longueur des chaînes. Les seuls nombres dont vous avez besoin pour trier les bulles sont ceux de la même longueur.
La complexité ici est N ^ 3.
Pour être juste, cela dépend de la distribution des données d'entrée. Si la longueur de la chaîne est limitée, la complexité est N ^ 3.
Si vous faites deux types de bulles, ce n'est que 2 * (n ^ 2), pas n ^ 3.
Vous ne faites pas deux sortes de bulles. Et même si vous le faisiez, ce serait O (N ^ 2). Tout comme trois types de bulles, quatre sortes de bulles, etc.
Oui tu fais. Commencez par trier par longueur (n ^ 2) / 2, puis énumérez les groupes n, puis triez par bulles chaque longueur (n ^ 2) / 2. Résultats: (n ^ 2) + n.
Eh bien non, OrderBy n'est pas un tri à bulles. Et pour l'analyse de la complexité, vous ignorez les multiplicateurs constants. Ce qui compte, c'est la croissance avec N, pas la durée de chaque itération.
Lorsque vous comparez la complexité, il y a des cas où vous considérez un multiplicateur constant comme lorsque vous essayez de décider quel algorithme utiliser. Le pire cas de complexité est de l'ordre de n ^ 2 et nulle part près de n ^ 3. Avec le regroupement, le pire des cas est lorsque vous avez un groupe (toutes les chaînes de la même longueur). Au fur et à mesure que vous avez plus de groupes, la complexité diminue à n (toutes les chaînes de longueur différente où aucun tri n'est requis).
Si nous voulons trier de très gros nombres stockés sous forme de chaînes, sans changer la chaîne en BigInteger , il vaut mieux les trier en fonction de sa longueur au début, puis selon l'ordre lexicographique. Nous pouvons voir l'exemple de code ci-dessous:
using System;
using System.Linq;
public class Test
{
public static void Main()
{
string[] unsorted = { "1","2", "100","12303479849857341718340192371",
"3084193741082937","3084193741082938","111","200" };
unsorted.OrderBy(s => s.Length).ThenBy(s => s);
Console.WriteLine("Sorted numbers are:");
foreach (var x in unsorted) {
Console.WriteLine(x);
}
}
}
Remarque: pour utiliser les fonctionnalités OrderBy et ThenBy , nous devons inclure en utilisant System.Linq dans notre programme.
Pour une solution élégante, vous pouvez utiliser linq , vous aurez un minimum de code avec de bonnes performances.
var result = unsorted.Select(e => decimal.Parse(e)).OrderBy(e => e);
Si vous allez utiliser decimal , vous devriez probablement avertir l'OP de sa limitation (c'est-à-dire 16 octets maximum). Bien que cela fonctionne pour les exemples dans les questions, ajoutez un autre chiffre au quatrième chiffre et decimal.Parse () échouera.
@ahmed Je suis d'accord avec vous, mais la question était de savoir comment commander une table contenant des nombres selon un format de chaîne. Personnellement, je mettrais en question la raison de l'utilisation d'une chaîne à la place d'un entier.
Le système doit être comme suit. Vous pouvez transférer les valeurs du tableau vers une arraylist, puis les analyser toutes en BigInteger par boucle for. Et enfin vous pouvez trier la liste:
BigInteger[] unsorted;
var bigIntegers = new List<System.Numerics.BigInteger>();
for (int index = 0; index < unsorted.Length - 1; index++)
{
bigIntegers[i] = BigInteger.Parse[i]
}
bigIntegers.sort();
Une autre variante:
static void Main(string[] args)
{
List<string> unsorted = new List<string>(new string[] {"1","2","100","12303479849857341718340192371",
"3084193741082938","3084193741082937", "111","200" });
unsorted.Sort((x, y) => (x.Length != y.Length ? x.Length.CompareTo(y.Length) : x.CompareTo(y)));
foreach(string number in unsorted)
{
Console.WriteLine(number);
}
Console.Write("Press Enter to quit");
Console.ReadLine();
}
S'appuyant sur la réponse de @ jdweng , mais en la réduisant davantage en éliminant le tri à bulles "manuel":
using System.Collections.Generic;
using System.Linq;
...
string[] result =
unsorted.OrderBy(x => x, Comparer<string>.Create((a, b) => a.Length == b.Length ? a.CompareTo(b) : a.Length - b.Length))
.GroupBy(x => x.Length)
.SelectMany(x => x)
.ToArray();
Ou une autre variante du même thème:
string[] result =
unsorted.OrderBy(x => x.Length)
.GroupBy(x => x.Length)
.SelectMany(x => x.OrderBy(y => y))
.ToArray();
(Comme indiqué par le commentaire de @ fester sous la réponse de @ jdweng, cette approche ne fonctionnera pas de manière fiable si certaines des chaînes sont des nombres avec des zéros préfixés, comme " 00123 " par exemple.)
Vous pouvez utiliser BigInteger.Parse et utilisez le OrderBy de Linq dessus. Par exemple:
var sorted = unsorted.Select(BigInteger.Parse).OrderBy(e => e).Select(e => e.ToString()).ToArray();
Si vous en avez besoin en tant que chaîne:
var sorted = unsorted.Select(BigInteger.Parse).OrderBy(e => e).ToArray();
Cela a un inconvénient à le convertir d'abord en BigInteger , mais vous en avez probablement besoin de toute façon. Cependant, comparé à l'accès aux E / S et à la base de données, ce rien n'ajoute aux performances d'une application typique.
package com.solution.sorting;
import java.util.Arrays;
import java.util.Comparator;
public class ArraySort {
public static void main(String[] args) {
String[] number = { "3", "2", "4", "10", "11", "6", "5", "8", "9", "7" };
String[] unsorted = { "8", "1", "2", "100", "12303479849857341718340192371", "3084193741082937",
"3084193741082938", "111", "200" };
Arrays.sort(number);
for (String s : number)
System.out.println("number="+s);
//
Arrays.sort(unsorted, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return compareStrings(o1,o2);//Integer.valueOf(o1).compareTo(Integer.valueOf(o2));
}
});
for (String s : unsorted)
System.out.println("number1=" + s);
}
private static int compareStrings(String s1, String s2) {
//
if (s1.length() < s2.length()) {
return -1;
} else if (s1.length() > s2.length()) {
return 1;
}
for (int i = 0; i < s1.length(); i++) {
if ((int) s1.charAt(i) < (int) s2.charAt(i))
return -1;
if ((int) s1.charAt(i) > (int) s2.charAt(i))
return 1;
}
return 0;
}
}
Le compte pour la boucle, il vous suffit de comparer des nombres de même longueur. Je ferais donc ce qui suit: var groups = unsorted.OrderBy (x => x.length) .GroupBy (x => x.Length), ToArray ();