Les matrices clairsemées, également appelées tableaux clairsemés, sont des structures de données utilisées pour représenter des matrices dont la plupart des éléments sont nuls ou indéfinis. Contrairement aux matrices traditionnelles, les matrices clairsemées ne stockent que les éléments non nuls, ce qui les rend efficaces pour stocker de grandes matrices avec un grand nombre de zéros.
La mise en œuvre de matrices clairsemées à l'aide de hashmaps peut être inefficace pour les données fréquemment lues, car les hashmaps introduisent des collisions. pour la lecture et l'écriture, nécessitant des fonctions de hachage complexes et des boucles pour gérer chaque position candidate et la comparer avec l'index source.
Une approche plus efficace consiste à utiliser une structure Trie (Trie Radix Tree) qui permet un accès direct à un seul vecteur où les segments sont distribués. Les essais peuvent déterminer la présence d'un élément dans la table avec seulement deux opérations d'indexation de tableau, offrant un accès rapide en lecture seule et une position par défaut dans le magasin de sauvegarde pour les valeurs par défaut.
Cette approche évite tout test sur le retour index, garantit que tous les index sources correspondent au moins à la position par défaut dans le magasin de sauvegarde et prend en charge les essais pouvant être mis à jour rapidement avec une opération facultative "compact()" pour optimiser l'espace de stockage à la fin de plusieurs opérations.
Les essais sont nettement plus rapides que les hashmaps car ils ne nécessitent pas de fonctions de hachage complexes ni de gestion des collisions, et ils fonctionnent efficacement avec Java IntegerTrieMap et LongTrieMap pour les indices Integer et Long, bien qu'ils ne soient actuellement pas inclus dans le JRE.
Exemple de code :
<code class="java">public class DoubleTrie { // Matrix options public static final int SIZE_I = 1024; public static final int SIZE_J = 1024; public static final double DEFAULT_VALUE = 0.0; // Internal splitting options private static final int SUBRANGEBITS_I = 4; private static final int SUBRANGEBITS_J = 4; // Internal derived splitting constants private static final int SUBRANGE_I = 1 << SUBRANGEBITS_I; private static final int SUBRANGE_J = 1 << SUBRANGEBITS_J; private static final int SUBRANGEMASK_I = SUBRANGE_I - 1; private static final int SUBRANGEMASK_J = SUBRANGE_J - 1; private static final int SUBRANGE_POSITIONS = SUBRANGE_I * SUBRANGE_J; // Internal derived default values for constructors private static final int SUBRANGES_I = (SIZE_I + SUBRANGE_I - 1) / SUBRANGE_I; private static final int SUBRANGES_J = (SIZE_J + SUBRANGE_J - 1) / SUBRANGE_J; private static final int SUBRANGES = SUBRANGES_I * SUBRANGES_J; private static final int DEFAULT_POSITIONS[] = new int[SUBRANGES]; private static final double DEFAULT_VALUES[] = new double[SUBRANGE_POSITIONS](DEFAULT_VALUE); // Internal fast computations private static final int subrangeOf(int i, int j) { return (i >> SUBRANGEBITS_I) * SUBRANGE_J + (j >> SUBRANGEBITS_J); } private static final int positionOffsetOf(int i, int j) { return (i & SUBRANGEMASK_I) * SUBRANGE_J + (j & SUBRANGEMASK_J); } // Internal member variables private double values[]; private int subrangePositions[]; private boolean isSharedValues; private boolean isSharedSubrangePositions; // Internal method private final void reset(double[] values, int[] subrangePositions) { this.isSharedValues = (this.values = values) == DEFAULT_VALUES; this.isSharedSubrangePositions = (this.subrangePositions = subrangePositions) == DEFAULT_POSITIONS; } // Reset method public void reset(double initialValue = DEFAULT_VALUE) { reset((initialValue == DEFAULT_VALUE) ? DEFAULT_VALUES : new double[SUBRANGE_POSITIONS](initialValue), DEFAULT_POSITIONS); } // Default constructor public DoubleTrie(double initialValue = DEFAULT_VALUE) { this.reset(initialValue); } // Immutable default instance public static DoubleTrie DEFAULT_INSTANCE = new DoubleTrie(); // Copy constructor public DoubleTrie(DoubleTrie source) { this.values = (this.isSharedValues = source.isSharedValues) ? source.values : source.values.clone(); this.subrangePositions = (this.isSharedSubrangePositions = source.isSharedSubrangePositions) ? source.subrangePositions : source.subrangePositions.clone(); } // Fast indexed getter public double getAt(int i, int j) { return values[subrangePositions[subrangeOf(i, j)] + positionOffsetOf(i, j)]; } // Fast indexed setter public double setAt(int i, int j, double value) { int subrange = subrangeOf(i, j); int positionOffset = positionOffsetOf(i, j); // Check if the assignment will change anything int subrangePosition, valuePosition; if (Double.compare(values[valuePosition = (subrangePosition = subrangePositions[subrange]) + positionOffset], value) != 0) { // The assignment will change something, check if the affected subrange is shared if (isSharedValues) { values = values.clone(); isSharedValues = false; } // Scan all other subranges to check if the affected position is shared for (int otherSubrange = subrangePositions.length; --otherSubrange >= 0;) { if (otherSubrange != subrange) { continue; // Ignore the target subrange } // Check if the target position is shared by another subrange if ((otherSubrangePosition = subrangePositions[otherSubrange]) >= valuePosition && otherSubrangePosition + SUBRANGE_POSITIONS < valuePosition) { // The target position is shared, we need to make it unique by cloning the subrange and copying all its values to the end of the new vector if (isSharedSubrangePositions) { subrangePositions = subrangePositions.clone(); isSharedSubrangePositions = false; } values = DoubleTrie.arraysetlength(values, (subrangePositions[subrange] = subrangePositions = values.length) + SUBRANGE_POSITIONS); valuePosition = subrangePositions + positionOffset; break; } } // Assign the new value values[valuePosition] = value; } return value; } // Compact storage method public void compact() { int oldValuesLength = values.length; int newValuesLength = 0; for (int oldPosition = 0; oldPosition < oldValuesLength; oldPosition += SUBRANGE_POSITIONS) { int oldPosition = positions[subrange]; boolean commonSubrange = false; // Scan values for possible common subranges for (int newPosition = newValuesLength; (newPosition -= SUBRANGE_POSITIONS) >= 0;) { if (arrayequals(values, newPosition, oldPosition, SUBRANGE_POSITIONS)) { commonSubrange = true; // Update the subrangePositions with all matching positions from oldPosition to newPosition for (subrange = subrangePositions.length; --subrange >= 0;) { if (subrangePositions[subrange] == oldPosition) { subrangePositions[subrange] = newPosition; } } break; } } if (!commonSubrange) { // Move down the non-common values if (!commonSubrange && oldPosition != newValuesLength) { DoubleTrie.arraycopy(values, oldPosition, newValuesLength, SUBRANGE_POSITIONS); newValuesLength += SUBRANGE_POSITIONS; } } } // Check the number of compressed values if (newValuesLength < oldValuesLength) { values = values.arraysetlength(newValuesLength); isSharedValues = false; } } }</code>
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!