2009-09-24 6 views
0

J'ai 2 ensembles d'entiers non triés: définir A et définir B. Mais nous ne savons pas combien d'éléments sont présents dans setB à l'avance.Recherche d'un moyen efficace de trouver un ordre trié à partir de 2 listes

Je dois:

while setA and setB are not empty: 
    pop the smallest no from setA 
    move an int from setB to setA 

Quelle est la façon la plus efficace de le faire en Java?

Je pense

  1. créer un ArrayList pour Seta et LinkedList pour SetB
  2. while (SETA et SetB ne sont pas vides) tri (SETA) pop Seta supprimer un entier de SetB et insert dans setA

Existe-t-il une meilleure façon de faire cela en Java? Je voudrais supprimer le 'tri dans la boucle while' si possible.

+1

le problème est pas clair. Pourquoi avons-nous besoin de déplacer int de B vers A? quel est le but de toute cette opération? o_O –

Répondre

1
TreeSet<Integer> setA = new TreeSet<Integer>(listA); 
TreeSet<Integer> setB = new TreeSet<Integer>(listB); 
while (!setA.isEmpty()) { 
    setA.remove(setA.first()); 
    if (!setB.isEmpty()) { 
     Integer first = setB.first(); 
     setB.remove(first); 
     setA.add(first); 
    } 
} 

Explication: la classe TreeSet maintient l'ensemble dans un arbre rouge-noir qui est commandé sur ordre naturel des éléments de réglage; c'est-à-dire la méthode Integer.compareTo() dans ce cas. L'ajout ou la suppression d'un élément trouve l'emplacement approprié dans l'arborescence de l'élément, puis l'ajoute ou le supprime sans qu'il soit nécessaire de trier.

Le procédé isEmpty est O (1), et les first, addremove et méthodes sont tous O (log N), où chacun doit être appelé O (n) fois. La création des premiers arbres est également O (N log N). Donc, la complexité globale va être O (N log N) où N est la taille totale de la liste.

+2

Il semble qu'il n'y ait aucune exigence que les éléments soient supprimés de setB dans l'ordre, de sorte que vous pouvez éviter de créer un nouvel TreeSet et simplement utiliser un Iterator via setB, en supprimant les éléments lorsqu'ils sont récupérés. – Ken

+0

@Ken: Vrai ... mais d'un autre côté il n'est pas clair à partir de la question si les entrées sont vraiment des ensembles d'ordre indéterminé (par exemple HashSets) ou des listes.Dans le premier cas, faire un 'setB' un TreeSet aboutit à un résultat plus prévisible. –

0

Voici ce que j'ai compris de la question: Nous avons besoin d'une collection triée qui contient tous les éléments de setA et de setB. Parce que setA et setB peuvent contenir des éléments égaux, nous devrions utiliser une liste (conserve les doublons). Si nous ne voulons pas de doublons, échangez simplement ArrayList par TreeSet et supprimez le tri supplémentaire. Je suppose que les deux ensembles contiennent le même type d'éléments - sinon, nous pouvons toujours utiliser Collections.sort mais nous devons pousser un comparateur à la méthode de tri capable de comparer différents types d'objets.

private Collection<Integer> combineAndSort(Set<Integer>...sets) { 
    Collection<Integer> sorted = new ArrayList<Integer>(); 
// Collection<Integer> sorted = new TreeSet<Integer>(); 
    for(Set<Integer> set:sets) { 
     sorted.addAll(set); 
    } 
    Collections.sort(sorted); // obsolete if using TreeSet 
} 
+0

@Andreas: bien que je ne comprenne pas la logique de l'algorithme de l'OP, votre code ne fait pas la même chose que son algorithme. –

+0

Oui, la façon la plus simple de démontrer l'écart est avec un A non vide et un B vide. L'algorithme original ne va pas itérer du tout, alors que le vôtre le fera. –

+0

convenu - je n'étais pas sûr que son algorithme résoudrait le problème, alors j'ai décidé de m'en tenir au problème qui était donné dans le titre des questions;) –

0

Si vous utilisez Java 5 partir, pensez java.util.PriorityQueue:

Collection<Integer> setA = ...; 
Collection<Integer> setB = ...; 
if (setA.isEmpty()) { 
    // if A is empty, no need to go on. 
    return; 
} 
PriorityQueue<Integer> pq = new PriorityQueue<Integer>(setA); 
Iterator<Integer> iterB = new LinkedList<Integer>(setB).iterator(); 
// no need to check if A is empty anymore: starting off non-empty, 
// and for each element we remove, we move one over from B. 
while (iterB.hasNext()) { 
    int smallest = pq.poll(); 
    doStuffWithSmallest(smallest); 
    pq.add(iterB.next()); 
    iterB.remove(); 
} 

Notez que dans le code ci-dessus, je suis d'abord Enveloppez la SetB dans une liste, pour soutenir une élimination efficace. Si votre setB prend en charge une suppression efficace, vous n'avez pas besoin de l'envelopper. Notez également que, puisque vous ne se soucient pas des éléments mobiles de la devant SetB, un ArrayList peut prendre en charge l'élimination très efficace:

private <T> T removeOne(ArrayList<T> array) throws IndexOutOfBoundsException { 
    return array.remove(array.size() - 1); 
} 
Questions connexes