2010-04-19 21 views
3

J'essaie de créer une liste d'adjacence pour stocker un graphique. L'implémentation fonctionne correctement lors du stockage de 100 000 enregistrements. Cependant, quand j'ai essayé de stocker environ 1 million de dossiers je suis tombé Erreur de mémoire saturée:création de liste d'adjacence, erreur de mémoire insuffisante

Exception dans le thread « principal » java.lang.OutOfMemoryError: espace de tas Java à java.util.Arrays.copyOfRange (Arrays.java: 3209) à java.lang.String. (String.java:215) à java.io.BufferedReader.readLine (BufferedReader.java:331) à java.io.BufferedReader.readLine (BufferedReader.java:362) à liarliar.main (liarliar.java:39)

Après ma mise en œuvre

HashMap<String,ArrayList<String>> adj = new HashMap<String,ArrayList<String>>(num); 


     while ((str = in.readLine()) != null) 
     { 

      StringTokenizer Tok = new StringTokenizer(str); 
      name = (String) Tok.nextElement(); 
      cnt = Integer.valueOf(Tok.nextToken()); 
      ArrayList<String> templist = new ArrayList<String>(cnt); 

      while(cnt>0) 
      { 
        templist.add(in.readLine()); 
        cnt--; 
      } 
      adj.put(name,templist); 

     } //done creating a adjacency list 

Je me demande, s'il y a une meilleure façon d'implémenter la liste d'adjacence. De plus, je connais le nombre de nœuds au début et, à l'avenir, j'aplatirai la liste lorsque je visiterai des nœuds. Aucune suggestion ?

Merci

Répondre

1

Il me semble avoir un avantage injuste ici que je reconnais à la fois le nom du problème (liarliar) et la nature exacte de l'entrée.

Je peux vous dire que ce OutOfMemoryError est voulu. Vous devez trouver un meilleur algorithme qui ne stocke pas toute l'information d'adjacence du graphe en mémoire. Je vais m'abstenir de donner trop d'informations algorithmiques, mais je peux vous dire que vous devez vous asseoir et penser plus que ce que vous avez besoin de programmer à ce stade. Peut-être lire un bon livre sur les algorithmes et les structures de données.


Ce que vous faites est en ce moment que vous stockez réellement les chaînes à partir du fichier d'entrée inutilement dans votre HashMap<String,ArrayList<String>>. Ceci est très inefficace en raison de la nature du problème.

C'est beaucoup plus facile et beaucoup plus efficace si vous utilisez un java.util.Scanner à la place. new Scanner(new File(inputFilename)) et next(), et nextInt() sont tout ce dont vous avez besoin.

Affectez un int unique à chaque nom (indice: Map<String, Integer>) et stockez le int beaucoup plus petit à la place.

0

Merci d'avoir répondu à ma question. Oui, vous l'avez deviné, de quoi parle le code.

Je pense que oui, l'utilisation d'un mappage de chaîne à des entiers permettrait de gagner de l'espace pour la liste d'adjacence. Dans ce sens, l'erreur ci-dessus peut être supprimée.

Cependant, j'ai utilisé java -jar -Xmx1024M. Cela donne un moyen d'exécuter le programme avec plus de mémoire de tas, et puisqu'il est autorisé à l'utiliser dans le prolem donné, cela ne sera pas la raison pour laquelle ma soumission échoue.

Les performances peuvent être l'une des raisons de l'échec du bot mais je ne suis pas sûr.

En ce qui concerne votre solution,

Si je crée une carte, puis stocker les numéros dans la liste des adjacencey il me sauver un peu d'espace, mais il faudra également ajouter une recherche supplémentaire chaque fois que je besoin d'accès un noeud pendant ma traversée bfs/dfs. Cela me dérange. Êtes-vous en train de dire que je ne devrais pas créer la liste d'adjacence du tout? Ai-je compris ce que vous essayez de dire correctement?

merci.

+0

Une recherche 'Map ' est bon marché ('O (1)'); Vous ne devriez pas en être dérangé à moins que cela ne prouve qu'il y a un problème. L'optimisation prématurée est la racine de tous les maux. C'est encore plus vrai dans ce cas, car il y a une optimisation _BIG_ que vous n'avez toujours pas découverte. Vous m'avez bien compris: vous n'avez pas à créer la liste d'adjacence du tout. Vous pouvez résoudre ce problème dans l'espace 'O (V)'. Vous pouvez traiter l'entrée dans 'O (V + E)' (ce qui est optimal, puisque c'est la taille de l'entrée), et une fois que vous avez fini de lire l'entrée, vous pouvez produire la sortie dans 'O (1) '. – polygenelubricants

+0

Une autre façon d'économiser de l'espace sans utiliser le 'Map ' est de '.intern()' les chaînes. Beaucoup de noms se répètent dans l'entrée, et ils sont stockés de manière redondante dans la mémoire plusieurs fois. Si vous ne stockez que '.intern()' de ces noms, les copies redondantes seront récupérées. Et en bonus, si vous avez toujours '.intern()' les noms, vous pouvez utiliser '==' et '! =' Au lieu de 'equals()'. Lisez à propos de comment l'internalisation de chaînes fonctionne. C'est une petite optimisation du temps, cependant. Le vraiment important est celui dans le commentaire ci-dessus. – polygenelubricants

+0

Je sais que ça a à voir avec le test de bipartite/coloration des graphes .. mais je pense toujours dans ma tête pour avoir une réponse dans O (1) juste après avoir créé une carte (nom, int) de tous les nœuds !! L'int dans Map (nom, int) peut changer selon la distance, tout va même dans 1 groupe et impair dans l'autre .. Problème avec toutes ces approches, Il nécessite une liste d'adjacence :(pour assurer que le graphique est tracée Au format BFS ou DFS, sinon vous vous retrouvez avec un nouveau noeud ne sachant pas à quel groupe appartient le noeud .. il devient donc difficile de savoir à quels noeuds les enfants iraient Il me manque quelque chose, suis-je sur la bonne voie? – codeObserver