Warning This class is being recorded.
Approximate overview
Academic
Cultural
Peer
Wellness
Misc
Expandable array code: ExpandableStringArray.java
Our experiments: ESAexpt.java
Philosophy: Like an array, but automatically “expands” if we set something beyond the assumed “size” of the array.
Use Cases: Similar to those for which we use arrays.
Methods (minimalist): An expandable array might provide three primary methods.
String ExpandableArray(String default)
- Create a new expandable array
of the specified size.void set(int index, String val)
- Set the value at the given index to
val
.String get(int index)
- If we’ve set something at the given index using
set
, return that value. Otherwise, return default
.We might also provide a few other basic methods
void addToEnd(String val)
- add to the end of the “useful” valuesint size()
: 1 + largest index usedReminder: At first, only add the methods that (a) make sense within the context of the purpose and (b) cannot be implemented by the other methods you’ve written.
One could argue that once you have size()
, you no longer need addToEnd()
.
arr.addToEnd(val) = arr.set(arr.size(), val);
Layout: We’re storing the array as a normal array. We’ll have to allocate a bigger underlying array (and copy things over) when it needs to expand.
Good alternate idea: A linked list of arrays.
What fields do you want in the class?
public class ExpandableStringArray {
// +--------+------------------------------------------------------
// | Fields |
// +--------+
/**
* The "size"; the largest index used so far.
*/
int size;
/**
* The underlying array.
*/
String[] values;
/**
* The default value (used for cells that haven't been set).
*/
String default;
} // class ExpandableStringArray
Implementation
get
?set
?size()
?addToEnd()
? (Done)get
public String get(int i) {
if ((i < 0) || (i > this.values.length)) {
return this.default;
} else {
return this.values[i];
} // if ... else
} // get(int)
set
default
being in all the unset locations, we need to put it ther. public void set(int i, String val) {
// If the index is too large
if (i > this.values.length) {
// Build a new array and copy it over
String[] newvalues = new String[i+1];
for (int j = 0; j < this.values.length; j++) {
newvalues[j] = this.values[j];
} // for
for (int j = this.values.length; j < i; j++) {
newvalues[j] = this.default;
} // for
this.values = newvalues;
} // if
this.values[i] = val;
this.size = max(this.size, i+1);
} // set(int, String)
Constructor
private static final int INITIAL_ARRAY_SIZE = 16;
public ExpandableStringArray(String default) {
this.values = new String[INITIAL_ARRAY_SIZE];
this.default = default;
this.size = 0;
for (int i = 0; i < this.values.length; i++) {
this.values[i] = default;
} // for
} // ExpandableStringArray
size
/**
* Get the size (1 + the largest index used for set).
*/
public int size() {
return this.size;
}
Note: The code above is not correct. We made some changes in the example. Look there.
Analysis
We skipped over an important design decision. When expanding the array, how much should we expand it?
i + 1
this.values.length * 2
Hint: There are flaws in both options.
for (int i = 0; i < 1000; this.addToEnd("" + i);
this.values.length * 2
.Our best option is either
max(i+1, this.values.length*2)
Important moral: Double array sizes if you need to expand them. There’s a little extra expense now, but amortized over all the expansions, it’s much better than a constant size expansion.