The following is obviously very impractical but my lecturer insists on teaching us a very fundamental understanding of programming. The exercise he gave us goes like this:
Using only System.in.read, int, char, and loops, create a method that reads
user input from the command line and returns a char[] that's exactly as big as the amount
of characters that were entered. Do not use System.arraycopy() or other library methods.
I'm clueless. Since there seems to be no way of buffering System.in.read input, the array would have to be perfectly sized before any chars are parsed. How in the world is this supposed to work?
create a method that reads user input from the command line and returns a char[]
On a second thought, I assume that you are supposed to do your own input buffering by growing a char[] array yourself. That should be the reason why System.arraycopy() is mentioned.
Growing an array works like
create a new array that is 1 item longer than the existing one.
for each character in the old array
copy the character from the old to the new array, keeping the position
replace the old array with grown array.
If you combine that with a loop that reads all characters from the inputstream you get about the following and should be done with your assignment.
start with array of length 0
while character available from inputstream
grow the array one larger
put the character from inputstream into the last slot of the array
return array
It is even possible to do it without loops and growing arrays. Just creating a new array of the correct size once.
private static char[] readToCharArray(int length) throws IOException {
int read = System.in.read();
char[] result;
if (read == -1 || read == '\r' || read == '\n' ) {
result = new char[length];
} else {
result = readToCharArray(length + 1);
result[length] = (char) read;
}
return result;
}
char[] myArray = readToCharArray(0);
what about manual arraycopy, the text doesn't say anything about that? if that is allowed you could do something like this:
private static char[] readInput() throws IOException {
System.out.println("type something terminated with '|'");
char[] input = new char[0];
int count = 0;
int read;
for (; ; ) {
read = System.in.read();
if (read == '|') {
break;
} else {
char[] tmp = new char[input.length + 1];
for (int i = 0; i < input.length; i++) {
tmp[i] = input[i];
}
input = tmp;
}
input[count] = (char) read;
count++;
}
return input;
}
you could also check for read == -1 instead of read == '|' but the end-of-input character differs from system to system. Instead of copying the char[] on every iteration you could also do it every x iterations and then at the end create an array of the correct size. You could also use a while loop...
But it would be definitely more fun to just return an empty array of the correct size as zapl suggested :)
I'm going to assume that your lecturer meant:
The char[] should contain the characters that were read from System.in (not just be the right size)
"System.in.read" refers only to InputStream#read() and not to the other overloaded read methods on InputStream, so you're constrained to reading one character at a time.
You should look at the way ArrayList is implemented. It is backed by an array, yet the list is arbitrarily resizable. When the size of the list exceeds the array size, ArrayList creates a new array that is larger, and then copies the contents of the old array into it. Here are some relevant excerpts from ArrayList:
/**
* Appends the specified element to the end of this list.
*
* #param e element to be appended to this list
* #return <tt>true</tt> (as specified by {#link Collection#add})
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* #param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
Since you can't use System.arraycopy(), you'll need to write your own method to do that. That's just a for loop.
This isn't actually all that inefficient. As the javadoc describes, ArrayList#add(E) runs in amortized constant time.
If you follow the ArrayList strategy exactly, then your resulting array will be larger than it needs to be, so at the end, you'll need to do one more array resize at the end to truncate it to exactly the input size. Alternately, you could just grow the array by 1 every time you read a character, but the running time will be quadratic (n^2) rather than linear (n) in the input length.
Related
Note: I deleted this post earlier because I found the following post but I'm not sure how to apply it to my problem.
I'm working on a transposition cipher decoder. I have already solved the problem of static columns (1,2,3,4 kept in order), but I'm not sure how to create an array of each possible permutation of a length(Given as a parameter), I understand the easiest way is some kind of recursive method, but whilst attempting this I keep getting lost in the endeavour. (I've been coding all day and am quite tired)
Example array would contain:
1,2,3,4,5,6
2,1,3,4,5,6
2,3,1,4,5,6
...
After being very confused for awhile, and trying a few different things, a friend of mine (Not a user here) gave me the following java solution:
public static void main(String[] args) {
Nibba nib = new Nibba();
List<Character> characterSet = new ArrayList<>();
characterSet.add('1');
characterSet.add('2');
characterSet.add('3');
characterSet.add('4');
characterSet.add('5');
characterSet.add('6');
List<String> perms = nib.generatePermutations(characterSet);
// filter only the permutations of length 6
perms = perms.stream().filter(p -> p.length() == characterSet
.size()).collect(Collectors.toList());
for (String s : perms) {
System.out.println(s);
}
System.out.println("Total permutations = " + perms.size());
}
private List<String> generatePermutations(List<Character> characterSet) {
List<String> permutations = new ArrayList<>();
for (int idx = 0; idx < characterSet.size(); idx++) {
char character = characterSet.get(idx);
// Initialise first "permutation"
if (idx == 0) {
permutations.add(String.valueOf(character));
continue;
}
ArrayList<String> oldPerms = new ArrayList<>(permutations);
for (String subPermutation : oldPerms) {
insertPermutations(permutations, subPermutation, character);
}
}
return permutations;
}
/**
* Insert permutations into the given list
*
* #param list the list
* #param str the string
* #param c the character to insert at each point in the string
*/
private void insertPermutations(List<String> list, String str, char c) {
for (int i = 0; i <= str.length(); i++) {
String newStr = str.substring(0, i) + c + str.substring(i);
list.add(newStr);
}
}
Recall that there are n! permutations of n items. The n! can be easily understood in the following way:
1. There are `n` options for choosing the first item.
2. There are `n-1` items remaining from which to choose the second item
...
n-1. There are `2` options left for the `n-1`-th item.
n. There is only 1 item left for the `n`-th position.
Thus there are (n) * (n-1) * (n-2) * ... (2) * (1) = n! total choices for how to order the items.
This directly reveals a method for enumerating the permutations using a mixed-radix numbering scheme. In this scheme, the most-significant digit will be base n, the next-most-significant digit will be base n-1..etc.
You use such a mixed-radix number to select a permutation in the following way:
Use the most significant digit to select an element from the array (note that the first digit ranges from [0, n-1], and there are n elements to select from, so you can use it as the index of the item to select.)
Remove the selected element from the array, record that it's the first element of the permuted array, and compact the remaining elements to the front of the array.
Use the second-most significant digit to select an element from the remaining items (note that the value of this digit ranges from [0, n-2], and there are n-1 digits remaining)
Remove the selected element recording it as the second element in the permuted array
Repeat until all items have been selected.
If we use an array to represent the mixed-radix number in little-endian digit order, then we would have the following:
int mixed_radix[n] = {0};
You increment this mixed-radix number in the following way:
//Increment the least-significant digit
mixed_radix[0]++;
//Ripple overflow toward the most-significant digit
for(i=0; i<n; i++) {
if(mixed_radix[i] > i) {
mixed_radix[i] = 0;
if(i < n-1)mixed_radix[i+1]++;
}
else {
break;
}
}
So we have a way to initialize the mixed-radix number to zero, and then increment it through every possible value, stopping once it wraps back around to zero. (or after n!-1 increments...)
All that said, there's a lovely numerical trick that can make this even simpler: You can unpack that ugly mixed-radix number from an integer in the following way:
We know that there are n! permutations of n items; for any integer val in the range [0, n!-1] the following provides a bijective mapping between the integer value and a mixed-radix number:
int working = val; //val in the range [0, n!-1]
for(j=0 j<n; j++) {
mixed_radix[j] = working % (j+1);
working /= (j+1);
}
So embedding this "unpacking" loop within an outer loop that runs val over the range 0 to n!-1 is a much denser method to enumerate the mixed-radix numbers (which enumerates the possible permutations). It also assigns an integer to each permutation, effectively naming them. :)
This is my current progress on a project. I am trying to implement this ArrayList stuff but file continues to trow the same exception.
import java.util.*;
public class Numerican{
public static void main( String [] args ){
Scanner input = new Scanner(System.in);
ArrayList<Integer> array = new ArrayList<Integer>(10);
int count = input.nextInt() * 2;
while (count > 0){
array.add( 0 );
count = count - 1;
array.add(count, 2);
}
array.add(2, input.nextInt());
System.out.println(array.get(2));
}
}
It was my understanding that = new ArrayList<Integer>(10); would set the array size to 10. Did I do something wrong?
= new ArrayList<Integer>(10);
This line initializes the CAPACITY to 10, meaning the memory is allocated in the backend, but as far as you are concerned, the array is still empty.
Javadoc -
public ArrayList(int initialCapacity)
Constructs an empty list with the specified initial capacity.
This is why the calls to add might fail, if you try to add beyond the size of the ArrayList.
p.s. remember that add function takes index first and then element, when using the 2 parameter variant.
Edit:
ArrayList has 2 different member variables, size and capacity. Capacity is how much memory is allocated, size is how many elements are inserted by programmer.
Here, Capacity = 10, Size = 0;
According to the javadocs:
Constructs an empty list with the specified initial capacity.
Note that the ArrayList is empty (i.e. does not contain any items). The value indicates the capacity of the ArrayList which is the number of elements which can be added before more memory must be allocated.
On the other hand, calling add() actually adds an item to the ArrayList. In your example, array.add( 0 ); adds a 0 at the end of the list and array.add(count, 2); adds a 2 at index count. I suspect the problem is that count is not a valid index in your ArrayList. You should check what its value is by inserting an SOP or using a debugger.
count maybe >= 10, maybe souce code can answer you question:
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
rangeCheckForAdd():
/**
* A version of rangeCheck used by add and addAll.
*/
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
if the index is out of range (index < 0 || index > size()) IndexOutOfBoundsException will be thrown.
So i think you are accessing index > size() of the list.
size() ===> Returns the number of elements in this list.
array.add(2, input.nextInt()); here is the possible exception when your list size is 1...
From my understanding of ArrayList, you need to add items to the list in a sequential index.
i.e. You cannot add an item to the 7th index position if 1 to 6 have not been filled in.
ArrayList.add(indexPosition, element);
If you add elements to the list, starting at indexPosition 0, and increasing the indexPosition by 1 each time, it should work.
Ex.
int i = 0;
(while i < 10){
array.add(i, numberToAdd);
i++; }
Hey seems like your Problem is because of the line
array.add(count, 2);
adds a 2 at index count
For example your input size is 5 then array.add(9,2); the array size is only 1 by that time as capacity and size are two different parameters for a ArrayList. So you can use a for loop instead of while to insert your values
for(int i=0; i<count;i++)
{
array.add(i,2);
}
In the following code...
StringBuffer buf = new StringBuffer("Is is a far, far better thing that i do");
System.out.println("buf = "+ buf);
System.out.println("buf.length() = " + buf.length());
System.out.println("buf.capacity() = " + buf.capacity());
buf.setLength(60);
System.out.println("buf = "+ buf);
System.out.println("buf.length() = " + buf.length());
System.out.println("buf.capacity() = " + buf.capacity());
buf.setLength(30);
System.out.println("buf = "+ buf);
System.out.println("buf.length() = " + buf.length());
System.out.println("buf.capacity() = " + buf.capacity());
... the output is:
buf = Is is a far, far better thing that i do
buf.length() = 39
buf.capacity() = 55
buf = Is is a far, far better thing that i do
buf.length() = 60
buf.capacity() = 112
buf = Is is a far, far better thing
buf.length() = 30
buf.capacity() = 112
Consider how StringBuffer is typically used. When the String we need to store in a StringBuffer exceeds the current capacity, the current capacity is increased. If the algorithm only increased the capacity to the required amount, then StringBuffer would be very inefficient.
For example:
buf.append(someText);
buf.append(someMoreText);
buf.append(Another100Chars);
might require that the capacity be increased three times in a row. Every time the capacity is increased, the underlying data structure (an array) needs to be re-allocated in memory, which involves allocating more RAM from the heap, copying the existing data, and then eventually garbage collecting the previously allocated memory. To reduce the frequency of this happening, StringBuffer will double its capacity when needed. The algorithm moves the capacity from n to 2n+2. Here is the source code from AbstraceStringBuilder where this method is implemented:
/**
* This implements the expansion semantics of ensureCapacity with no
* size check or synchronization.
*/
void expandCapacity(int minimumCapacity) {
int newCapacity = value.length * 2 + 2;
if (newCapacity - minimumCapacity < 0)
newCapacity = minimumCapacity;
if (newCapacity < 0) {
if (minimumCapacity < 0) // overflow
throw new OutOfMemoryError();
newCapacity = Integer.MAX_VALUE;
}
value = Arrays.copyOf(value, newCapacity);
}
Every time you append to a StringBuffer or call setLength, this method is called:
public synchronized void ensureCapacity(int minimumCapacity) {
if (minimumCapacity > value.length) {
expandCapacity(minimumCapacity);
}
}
StringBuffer calls at several points the method expandCapacity. If it wouldn't oversize the capacity, it would have to allocate a new array, everytime you changes the Stringbuffers value. So this is some kind of performance optimization.
From the manual:
ensureCapacity
public void ensureCapacity(int minimumCapacity)
Ensures that the capacity is at least equal to the specified minimum.
If the current capacity is less than the argument, then a new internal
array is allocated with greater capacity. The new capacity is the
larger of:
* The minimumCapacity argument.
* Twice the old capacity, plus 2.
If the minimumCapacity argument is nonpositive, this method takes no
action and simply returns.
Parameters:
minimumCapacity - the minimum desired capacity.
A call to setLength(60) will cause ensureCapacity(60) to be called1.
ensureCapacity relies on "array doubling" which means that it will (at least) double the capacity each time it needs to be increased. The precise definition is documented in the Java Doc for ensureCapacity:
Ensures that the capacity is at least equal to the specified minimum. If the current capacity is less than the argument, then a new internal array is allocated with greater capacity. The new capacity is the larger of:
The minimumCapacity argument.
Twice the old capacity, plus 2.
If the minimumCapacity argument is nonpositive, this method takes no action and simply returns.
In your particular case, the second expression (in bold) is larger than the requested capacity, so this will be used. Since 2*55 + 2 equals 112, that's what the new capacity will be.
Related question:
Why is vector array doubled?
1) Actually, it will call extendCapacity but that behaves the same as ensure capacity.
This is a case of "read the free manual". From the Javadoc for StringBuffer -
public StringBuffer(String str)
Constructs a string buffer initialized to the contents of the specified string. The
initial capacity of the string buffer is 16 plus the length of the string argument.
which explains why it's initially 55. Then
public void ensureCapacity(int minimumCapacity)
Ensures that the capacity is at least equal to the specified minimum.
If the current capacity is less than the argument, then a new internal
array is allocated with greater capacity. The new capacity is the
larger of:
•The minimumCapacity argument.
•Twice the old capacity, plus 2.
If the minimumCapacity argument is
nonpositive, this method takes no action and simply returns.
explains why it changes to 112.
public synchronized void setLength(int newLength) {
super.setLength(newLength);
}
in super:
public void setLength(int newLength) {
if (newLength < 0)
throw new StringIndexOutOfBoundsException(newLength);
ensureCapacityInternal(newLength);
....
Then:
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0)
expandCapacity(minimumCapacity);
....
And finally:
void expandCapacity(int minimumCapacity) {
int newCapacity = value.length * 2 + 2;
....
Heap - Sort Algorithm
The problem I am having is this, this algorithms n input is 2, this is designed so that the 1st position (int i) of the array and the 2nd position (int j) have their values compared.
The problem is that this ignores the 0 position of the given array list. I have tried reducing certain values, this will create infinite loops. The algorithm is an adaptation of pseudocode. It isn't designed to run arraylist from 0. I can't think of how to re-adapt this algorithm into a decent minimum heap sort.
public static void input( ArrayList<input> vertexList, int n )
{
int j=n;
int i=n/2;
input object = vertexList.get(n);
while ((i>0) && vertexList.get(i)> object){
vertexList.set(j, vertexList.get(i));
j = i;
i = i/2;
}
vertexList.set(j, object);
}
try to use vertexList.get(i-1) and vertexList.get(j-1) and vertexList.set(j-1, ...)
I noticed that the capacity method returns StringBuilder capacity without a logic
way ... sometime its value is equals to the string length other time it's greater...
is there an equation for know which is its logic?
When you append to the StringBuilder, the following logic happens:
if (newCount > value.length) {
expandCapacity(newCount);
}
where newCount is the number of characters needed, and value.length is the current size of the buffer.
expandCapacity simply increases the size of the backing char[]
The ensureCapacity() method is the public way to call expandCapacity(), and its docs say:
Ensures that the capacity is at least equal to the specified minimum. If the current capacity is less than the argument, then a new internal array is allocated with greater capacity. The new capacity is the larger of:
The minimumCapacity argument.
Twice the old capacity, plus 2.
If the minimumCapacity argument is nonpositive, this method takes no action and simply returns.
I will try to explain this with some example.
public class StringBuilderDemo {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
System.out.println(sb.length());
System.out.println(sb.capacity());
}
}
length() - the length of the character sequence in the builder
since this stringbuilder doesn't contain any content, its length will be 0.
capacity() - the number of character spaces that have been allocated.
When you try to construct a stringbuilder with empty content, by default it takes the initialize size as length+16 which is 0+16. so capacity would return 16 here.
Note: The capacity, which is returned by the capacity() method, is always greater than or equal to the length (usually greater than) and will automatically expand as necessary to accommodate additions to the string builder.
The logic behind the capacity function:
If you don't initialize stringbuilder with any content, default capacity will be taken as 16 characters capacity.
If you initialize stringbuilder with any content, then capacity will be content length+16.
When you add new content to stringbuilder object, if current capacity is not sufficient to take new value, then it will grow by (previous array capacity+1)*2.
This analysis is take from actual StringBuilder.java code
This function does something different than you expect - it gives you the max number of chars this StringBuilder instance memory can hold at this time.
String Builder must read
Here's the logic:
If you define a new instance of the StringBuilder class without a constructor, like so new StringBuilder(); the default capacity is 16.
A constructor can be either an int or a String.
For a String constructor, the default capacity is calculated like this
int newCapacity = string.length() + 16;
For an int constructor, the capacity is calculated like this
int newCapacity = intSpecified + 16;
If a new String is appended to the StringBuilder and the new length of the String is greater than the current capacity, then the capacity is calculated like this:
int newCapacity = (oldCapacity + 1) * 2;
EDIT: Apologies - the below is information on .NET's StringBuilder, and is not strictly relevant to the original question.
http://johnnycoder.com/blog/2009/01/05/stringbuilder-required-capacity-algorithm/
StringBuilder allocates space for substrings you might add to it (much like List creates space the array it wraps). If you want the actual length of the string, use StringBuilder.Length.
From the API:
Every string builder has a capacity.
As long as the length of the character
sequence contained in the string
builder does not exceed the capacity,
it is not necessary to allocate a new
internal buffer. If the internal
buffer overflows, it is automatically
made larger.
Whenever you append something, there is a check to make sure that the updated StringBuilder won't exceed its capacity, and if it does, the internal storage of the StringBuilder is resized:
int len = str.length();
int newCount = count + len;
if (newCount > value.length)
expandCapacity(newCount);
When data is added to it that exceeds its capacity it is re-sized according to the following formula:
void expandCapacity(int minimumCapacity) {
int newCapacity = (value.length + 1) * 2;
if (newCapacity < 0) {
newCapacity = Integer.MAX_VALUE;
} else if (minimumCapacity > newCapacity) {
newCapacity = minimumCapacity;
}
value = Arrays.copyOf(value, newCapacity);
}
See the src.zip file that comes with the JDK for more information. (Above snippets taken from the 1.6 JDK)
You can go inside the JDK code and see how it works, it is based on a char array: new char[capacity], it is similar to how the ArrayList works (When to use LinkedList over ArrayList?). Both use arrays to be 'hardware efficient', the trick is to allocate a large chunk of memory and work in it until you run out of memory and need the next big chunk to continue (expand/grow).
in Java 1.8
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
for example :
StringBuilder str = new StringBuilder();
System.out.println(str.capacity()); //16
str.append("123456789012345");
System.out.println(str.capacity()); //16
str.append("12345678901234567890");
System.out.println(str.capacity()); // 15 + 20 = 35