7
votes

Mise en œuvre efficace des tableaux multidimensionnels en Java?

Aussi loin que je comprenne (des réponses telles que Ce ), Java n'a pas de réseau de mémoire continue multidimensionnelle natif ( Contrairement à C #, par exemple ).

Pendant que la syntaxe de tableau de jagghed (tableaux de tableaux) pourrait être bonne pour la plupart des applications, je voudrais toujours savoir quelle est la meilleure pratique si vous voulez que l'efficacité brude d'un réseau de mémoire continue (évitez les lectures de mémoire inutiles) < / p>

Je pouvais bien sûr utiliser un tableau monocensionnel qui correspond à un 2D, mais je préfère quelque chose de plus structuré.


4 commentaires

Je me sens comme si vous êtes micro optimisant. Mappage d'une matrice 1D sur un tableau 2D ne supprime que 1 allocution. Je ne peux pas imaginer que cela vous sauvera beaucoup / à tout moment.


Si vous avez besoin de toutes les performances, vous pouvez être mieux adapté à l'aide de C ou C ++.


Dans quelles circonstances pensez-vous que chaque rangée d'un tableau de deux dimensions étant contiguë avec la prochaine mémoire soit de manière significative plus efficace que l'arrare normale de Java de tableaux?


Je ne dis pas que c'est une optimisation critique , mais ce serait bien de savoir quelle est la meilleure pratique.


7 Réponses :


3
votes

Si vous voulez vraiment plus de structure avec une matrice de mémoire continue, enveloppez-la dans un objet.

public class My2dArray<T> {

  int sizeX;

  private T[] items;

  public My2dArray(int x, int y) {
    sizeX = x;
    items = new T[x*y];
  }

  public T elementAt(int x, int y) {
    return items[x+y*sizeX];
  }

}


2 commentaires

Vous pouvez également généraliser et supprimer le "2D" et mettre les dimensions en tant qu'argument Var-ARC au constructeur (et laissez le ellementat prenez un var-arg pour les indices)


Vrai, mais l'exemple démontre l'idée clé. Les chances sont bonnes qu'il a un tableau dimensionnel spécifique à l'esprit.



6
votes

Ce n'est pas difficile de le faire manuellement:

int x_i_j = matrix[i][j];


2 commentaires

Avec un seul tableau, cependant, vous ne feriez que la vérification des limites une fois au lieu de deux fois.


Si l'optimisation cache matricielle [i], c'est une vérification moins liée.



-1
votes

Si vous ne pouvez pas vivre sans Constructions C, il y a toujours JNI.

ou vous pouvez développer votre propre langue de dérivée Java (et VM et optimiser JIT Compiler) qui a une syntaxe pour les matrices de mémoire continue multidimensionnelles.


0 commentaires

1
votes

Exemplaire de mise en œuvre, sans compilateur. Ceci est fondamentalement ce que C / C ++ fait dans les coulisses lorsque vous accédez à des tableaux multidimensionnels. Vous devrez définir davantage le comportement des accesseurs lorsque moins que les dimensions réelles sont spécifiées et ainsi de suite. Les frais généraux seront minimes et pourraient être optimisés plus loin, mais c'est la microoptimisation de l'OMHO. En outre, vous ne savez jamais vraiment ce qui se passe sous la hotte après que Jit frappe.

class MultiDimentionalArray<T> {
//disclaimer: written within SO editor, might contain errors
    private T[] data;
    private int[] dimensions; //holds each dimensions' size

    public MultiDimensionalArray(int... dims) {
        dimensions = Arrays.copyOf(dims, dims.length);
        int size = 1;
        for(int dim : dims)
            size *= dim;
        data = new T[size];
    }

   public T access(int... dims) {
       int idx = 1;
       for(int i = 0; i < dims.length)
            idx += dims[i] * dimensions[i]; //size * offset
       return data[idx];
    }
}


0 commentaires

4
votes

Cela dépend de votre motif d'accès. Utilisation de Ce programme simple , comparant un int [] [] [] avec un 2D mappé sur un 1d int [] Traité traité comme une matrice, une matrice Java 2D natif est la suivante:

  1. 25% plus rapide lorsque la ligne est sur le cache, c'est-à-dire: accéder aux lignes:
  2. 100% plus ralentissé lorsque la ligne n'est pas dans le cache, c'est-à-dire: accéder par colums:

    IE: xxx

    La matrice 1D est calculée comme suit: xxx


2 commentaires

agréable. alors l'optimisation VM n'est pas aussi intelligente que je pensais.


Au contraire, JIT optimise la méthode des appels plus que de les aider à l'affiner. Appeler la méthode Get (X, Y) est plus rapide que d'accéder directement à la matrice de l'extérieur.



1
votes

La méthode la plus efficace de mise en oeuvre de matrices multidimensionnelles consiste à utiliser des réseaux unidimensionnels sous forme de réseaux multidimensionnels. Voir Cette réponse sur mapper un tableau 2D dans un tableau 1D.

public class ArrayInt {

    private final int[] array;
    private final int width, height;

    public ArrayInt(int width, int height) {
        array = new int[width * height];
        this.width = width;
        this.height = height;
    }

    public int getWidth() {
        return width;
    }

    public int getHeight() {
        return height;
    }

    public int get(int x, int y) {
        return array[x + y * width];
    }

    public void set(int x, int y, int value) {
        array[x + y * width] = value;
    }

}


0 commentaires

4
votes

disons que vous avez un tableau 2D int [] [] [] a = neuf int [hauteur] [largeur] , donc par convention, vous avez les indices a [y] [x] . Selon la manière dont vous représentez les données et la manière dont vous y accédez, la performance varie d'un facteur de 20:

 Comparaison de l'accès au tableau 2D

Le code: xxx

Nous pouvons conclure que les performances d'accès linéaire dépendent davantage de la manière dont vous traitez la matrice (lignes puis les colonnes ou l'inverse? la structure du tableau lui-même (1D vs 2D: Gain de performance = x2).

Si un accès aléatoire, les différences de performance doivent être beaucoup plus basses, car les caches de la CPU ont moins d'effet.


0 commentaires