/**
* Copyright 2010-2014 Jingjing Li.
*
* This file is part of jplot2d.
*
* jplot2d is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or any later version.
*
* jplot2d is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with jplot2d. If not, see .
*/
package org.jplot2d.util;
/**
* SparseIntArrays map integers to doubles. Unlike a normal array of doubles, there can be gaps in the indices. It is
* intended to be more memory efficient than using a HashMap to map Integers to Doubles, both because it avoids
* auto-boxing keys and values and its data structure doesn't rely on an extra entry object for each mapping.
*
*
* Note that this container keeps its mappings in an array data structure, using a binary search to find keys. The
* implementation is not intended to be appropriate for data structures that may contain large numbers of items. It is
* generally slower than a traditional HashMap, since lookups require a binary search and adds and removes require
* inserting and deleting entries in the array. For containers holding up to hundreds of items, the performance
* difference is not significant, less than 50%.
*
*
*
* It is possible to iterate over the items in this container using {@link #keyAt(int)} and {@link #valueAt(int)}.
* Iterating over the keys using keyAt(int) with ascending values of the index will return the keys in
* ascending order, or the values corresponding to the keys in ascending order in the case of valueAt(int).
*
*/
public class SparseDoubleArray implements Cloneable {
private static final int[] EMPTY_INTS = new int[0];
private static final double[] EMPTY_DOUBLES = new double[0];
private int[] mKeys;
private double[] mValues;
private int mSize;
/**
* Creates a new SparseIntArray containing no mappings.
*/
public SparseDoubleArray() {
this(10);
}
/**
* Creates a new SparseIntArray containing no mappings that will not require any additional memory allocation to
* store the specified number of mappings. If you supply an initial capacity of 0, the sparse array will be
* initialized with a light-weight representation not requiring any additional array allocations.
*/
public SparseDoubleArray(int initialCapacity) {
if (initialCapacity == 0) {
mKeys = EMPTY_INTS;
mValues = EMPTY_DOUBLES;
} else {
initialCapacity = idealIntArraySize(initialCapacity);
mKeys = new int[initialCapacity];
mValues = new double[initialCapacity];
}
mSize = 0;
}
@Override
public SparseDoubleArray clone() {
SparseDoubleArray clone = null;
try {
clone = (SparseDoubleArray) super.clone();
clone.mKeys = mKeys.clone();
clone.mValues = mValues.clone();
} catch (CloneNotSupportedException cnse) {
/* ignore */
}
return clone;
}
/**
* Gets the int mapped from the specified key, or 0 if no such mapping has been made.
*/
public double get(int key) {
return get(key, 0);
}
/**
* Gets the int mapped from the specified key, or the specified value if no such mapping has been made.
*/
public double get(int key, int valueIfKeyNotFound) {
int i = binarySearch(mKeys, mSize, key);
if (i < 0) {
return valueIfKeyNotFound;
} else {
return mValues[i];
}
}
/**
* Removes the mapping from the specified key, if there was any.
*/
public void delete(int key) {
int i = binarySearch(mKeys, mSize, key);
if (i >= 0) {
removeAt(i);
}
}
/**
* Removes the mapping at the given index.
*/
public void removeAt(int index) {
System.arraycopy(mKeys, index + 1, mKeys, index, mSize - (index + 1));
System.arraycopy(mValues, index + 1, mValues, index, mSize - (index + 1));
mSize--;
}
/**
* Adds a mapping from the specified key to the specified value, replacing the previous mapping from the specified
* key if there was one.
*/
public void put(int key, double value) {
int i = binarySearch(mKeys, mSize, key);
if (i >= 0) {
mValues[i] = value;
} else {
i = ~i;
if (mSize >= mKeys.length) {
int n = idealIntArraySize(mSize + 1);
int[] nkeys = new int[n];
double[] nvalues = new double[n];
// Log.e("SparseIntArray", "grow " + mKeys.length + " to " + n);
System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
mKeys = nkeys;
mValues = nvalues;
}
if (mSize - i != 0) {
// Log.e("SparseIntArray", "move " + (mSize - i));
System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
}
mKeys[i] = key;
mValues[i] = value;
mSize++;
}
}
/**
* Returns the number of key-value mappings that this SparseIntArray currently stores.
*/
public int size() {
return mSize;
}
/**
* Given an index in the range 0...size()-1, returns the key from the indexth key-value
* mapping that this SparseIntArray stores.
*
*
* The keys corresponding to indices in ascending order are guaranteed to be in ascending order, e.g.,
* keyAt(0) will return the smallest key and keyAt(size()-1) will return the largest key.
*
*/
public int keyAt(int index) {
return mKeys[index];
}
/**
* Given an index in the range 0...size()-1, returns the value from the indexth key-value
* mapping that this SparseIntArray stores.
*
*
* The values corresponding to indices in ascending order are guaranteed to be associated with keys in ascending
* order, e.g., valueAt(0) will return the value associated with the smallest key and
* valueAt(size()-1) will return the value associated with the largest key.
*
*/
public double valueAt(int index) {
return mValues[index];
}
/**
* Returns the index for which {@link #keyAt} would return the specified key, or a negative number if the specified
* key is not mapped.
*/
public int indexOfKey(int key) {
return binarySearch(mKeys, mSize, key);
}
/**
* Returns an index for which {@link #valueAt} would return the specified key, or a negative number if no keys map
* to the specified value. Beware that this is a linear search, unlike lookups by key, and that multiple keys can
* map to the same value and this will find only one of them.
*/
public int indexOfValue(int value) {
for (int i = 0; i < mSize; i++)
if (mValues[i] == value)
return i;
return -1;
}
/**
* Removes all key-value mappings from this SparseIntArray.
*/
public void clear() {
mSize = 0;
}
/**
* Puts a key/value pair into the array, optimizing for the case where the key is greater than all existing keys in
* the array.
*/
public void append(int key, double value) {
if (mSize != 0 && key <= mKeys[mSize - 1]) {
put(key, value);
return;
}
int pos = mSize;
if (pos >= mKeys.length) {
int n = idealIntArraySize(pos + 1);
int[] nkeys = new int[n];
double[] nvalues = new double[n];
// Log.e("SparseIntArray", "grow " + mKeys.length + " to " + n);
System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
mKeys = nkeys;
mValues = nvalues;
}
mKeys[pos] = key;
mValues[pos] = value;
mSize = pos + 1;
}
/**
* {@inheritDoc}
*
*
* This implementation composes a string by iterating over its mappings.
*/
@Override
public String toString() {
if (size() <= 0) {
return "{}";
}
StringBuilder buffer = new StringBuilder(mSize * 28);
buffer.append('{');
for (int i = 0; i < mSize; i++) {
if (i > 0) {
buffer.append(", ");
}
int key = keyAt(i);
buffer.append(key);
buffer.append('=');
double value = valueAt(i);
buffer.append(value);
}
buffer.append('}');
return buffer.toString();
}
// This is Arrays.binarySearch(), but doesn't do any argument validation.
private static int binarySearch(int[] array, int size, int value) {
int lo = 0;
int hi = size - 1;
while (lo <= hi) {
final int mid = (lo + hi) >>> 1;
final int midVal = array[mid];
if (midVal < value) {
lo = mid + 1;
} else if (midVal > value) {
hi = mid - 1;
} else {
return mid; // value found
}
}
return ~lo; // value not present
}
private static int idealIntArraySize(int need) {
for (int i = 4; i < 32; i++) {
if (need <= (1 << i) - 3) {
return (1 << i) - 3;
}
}
return need;
}
}
Ads help maintain this website.