I have a rank 3 int array array[9][3][3] and I want to convert it into a rank 2 array arrayConvt[9][9] by removing the major axis (rather than the middle axis). To make a 9x9 array rather than 3x27, imagine array broken up into 3 equal parts, each laid out into arrayConvt before the next. Note that the middle arrays (array[i]) do not remain contiguous in arrayConvt, but the innermost arrays (array[i][j]) do.
One way to visualize it is to look at array as an array of 9 blocks. I want to recombine the blocks left-to-right, top-to-bottom:
How can I reshape array according to this mapping?
The code sample below provides data to work with and the desired result:
public static void main(String[] args) {
int[][][] array = {
{
{0, 1, 2},
{10, 11, 12},
{20, 21, 22}
},
{
{100, 101, 102},
{110, 111, 112},
{120, 121, 122}
},
{
{200, 201, 202},
{210, 211, 212},
{220, 221, 222}
},
{
{300, 301, 302},
{310, 311, 312},
{320, 321, 322}
},
{
{400, 401, 402},
{410, 411, 412},
{420, 421, 422}
},
{
{500, 501, 502},
{510, 511, 512},
{520, 521, 522}
},
{
{600, 601, 602},
{610, 611, 612},
{620, 621, 622}
},
{
{700, 701, 702},
{710, 711, 712},
{720, 721, 722}
},
{
{800, 801, 802},
{810, 811, 812},
{820, 821, 822}
}
};
int[][] arrayConvt;
/*****
* What should go here to fill out `arrayConvt` using entries from `array` so it's equivalent to `array2d` below?
*/
int[][] array2d = {
{ 0, 1 , 2, 100, 101, 102, 200, 201, 202},
{ 10, 11, 12, 110, 111, 112, 210, 211, 212},
{ 20, 21, 22, 120, 121, 122, 220, 221, 222},
{300, 301, 302, 400, 401, 402, 500, 501, 502},
{310, 311, 312, 410, 411, 412, 510, 511, 512},
{320, 321, 322, 420, 421, 422, 520, 521, 522},
{600, 601, 602, 700, 701, 702, 800, 801, 802},
{610, 611, 612, 710, 711, 712, 810, 811, 812},
{620, 621, 622, 720, 721, 722, 820, 821, 822}
};
}
Try this.
public static void main(String[] args) {
int[][][] array = {
{{0, 1, 2}, {3, 4, 5}, {6, 7, 8}},
{{10, 11, 12}, {13, 14, 15}, {16, 17, 18}},
{{20, 21, 22}, {23, 24, 25}, {26, 27, 28}},
{{30, 31, 32}, {33, 34, 35}, {36, 37, 38}},
{{40, 41, 42}, {43, 44, 45}, {46, 47, 48}},
{{50, 51, 52}, {53, 54, 55}, {56, 57, 58}},
{{60, 61, 62}, {63, 64, 65}, {66, 67, 68}},
{{70, 71, 72}, {73, 74, 75}, {76, 77, 78}},
{{80, 81, 82}, {83, 84, 85}, {86, 87, 88}},
};
int[][] arrayConv = new int[9][9];
int[][] s = {
{0, 0}, {0, 3}, {0, 6},
{3, 0}, {3, 3}, {3, 6},
{6, 0}, {6, 3}, {6, 6},
};
for (int i = 0, p = 0; i < 9; ++i, ++p)
for (int j = 0, r = s[p][0]; j < 3; ++j, ++r)
for (int k = 0, c = s[p][1]; k < 3; ++k, ++c)
arrayConv[r][c] = array[i][j][k];
for (int[] r : arrayConv)
System.out.println(Arrays.toString(r));
}
output:
[0, 1, 2, 10, 11, 12, 20, 21, 22]
[3, 4, 5, 13, 14, 15, 23, 24, 25]
[6, 7, 8, 16, 17, 18, 26, 27, 28]
[30, 31, 32, 40, 41, 42, 50, 51, 52]
[33, 34, 35, 43, 44, 45, 53, 54, 55]
[36, 37, 38, 46, 47, 48, 56, 57, 58]
[60, 61, 62, 70, 71, 72, 80, 81, 82]
[63, 64, 65, 73, 74, 75, 83, 84, 85]
[66, 67, 68, 76, 77, 78, 86, 87, 88]
First, construct some source data
int src[][][] = new int[9][3][3];
for (int r = 0; r < 9; r++) {
for (int rr = 0; rr < 3; rr++) {
for (int cc = 0; cc < 3; cc++) {
src[r][rr][cc] = r * 9 + rr * 3 + cc + 1;
}
}
}
for (int[][] d : src) {
System.out.println(Arrays.deepToString(d));
}
prints
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
[[10, 11, 12], [13, 14, 15], [16, 17, 18]]
[[19, 20, 21], [22, 23, 24], [25, 26, 27]]
[[28, 29, 30], [31, 32, 33], [34, 35, 36]]
[[37, 38, 39], [40, 41, 42], [43, 44, 45]]
[[46, 47, 48], [49, 50, 51], [52, 53, 54]]
[[55, 56, 57], [58, 59, 60], [61, 62, 63]]
[[64, 65, 66], [67, 68, 69], [70, 71, 72]]
[[73, 74, 75], [76, 77, 78], [79, 80, 81]]
Now transform the matrix
int[][] dst = transform(src);
for (int[] row : dst) {
System.out.println(Arrays.toString(row));
}
prints
[1, 2, 3, 10, 11, 12, 19, 20, 21]
[4, 5, 6, 13, 14, 15, 22, 23, 24]
[7, 8, 9, 16, 17, 18, 25, 26, 27]
[28, 29, 30, 37, 38, 39, 46, 47, 48]
[31, 32, 33, 40, 41, 42, 49, 50, 51]
[34, 35, 36, 43, 44, 45, 52, 53, 54]
[55, 56, 57, 64, 65, 66, 73, 74, 75]
[58, 59, 60, 67, 68, 69, 76, 77, 78]
[61, 62, 63, 70, 71, 72, 79, 80, 81]
sr,sc - the source row and column of the inner 3x3 matrix to copy
r - the destination row to contain the above
the outer loop is used to create the destination row as well as allow
intermediate increments of key variables
and the JavaDoc explains System.arraycopy
public static int[][] transform(int[][][] src) {
int sr = 0;
int[][] dst = new int[9][9];
for (int x = 0; x < 3; x++) {
for (int sc = 0; sc < 3; sc++) {
int r = x * 3 + sc;
System.arraycopy(src[sr][sc], 0, dst[r], 0, 3);
System.arraycopy(src[sr + 1][sc], 0, dst[r], 3, 3);
System.arraycopy(src[sr + 2][sc], 0, dst[r], 6, 3);
}
sr = sr + 3;
}
return dst;
}
The best way of figuring out how to do this sort of thing is to play around with indices & reshaping, examining the resultant arrays. Once you do this, you notice a few things that can help you come up with more formal approaches.
One is to examine the mapping in terms of array index expressions. Since you want to map array[i][j][k] to arrayConvt[u][v], you need a way of expressing u and v in terms of i, j and k (or vice versa).
Calculate Destination Indices
Let's start with u. Note each array[i][j] remains contiguous in the result. Note also that array[i][j] is followed by array[i+1][j] (rather than array[i][j+1]) until you reach the end of arrayConvt. Thus, array[i..i+2][j] (where i is a multiple of 3), if flattened, becomes arrayConvt[j+x]. The x is present because the range of j doesn't quite match between array and arrayConvt, and so an adjustment is needed. Once the first 3 arrays in arrayConvt are filled, j goes back to 0, but j+x can go on to the next element of arrayConvt. As for where to get x, k is similarly limited in range, but i hasn't run through its range. Since j runs 0..2, it only needs to be combined with a multiple of 3, which we can get with (i / 3) * 3. This gives j + (i / 3)*3, which a quick mental check will show that it runs 0..8. Thus, u = j + (i / 3) * 3.
On to v. First note:
the minor index (k) in array[i][j][k] changes just as rapidly for arrayConvt and
the minor index for arrayConvt is independent of j
Thus v = k + f(i) (where f must be determined). Looking at how each arrayConvt[u] is layed out in terms of k and the 1D arrays from array[i][j] (<1D> #n in the diagram), we see something similar to how u related to i.
v | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
k | 0 | 1 | 2 | 0 | 1 | 2 | 0 | 1 | 2 |
| <1D> #0 | <1D> #1 | <1D> #2 |
i | 3a + 0 | 3a + 1 | 3a + 2 |
f(i) | 0 | 3 | 6 |
We can see that for any row of arrayConvt, i % 3 will range over 0..2. (i % 3) * 3 gives us f(i). Thus v = k + (i % 3) * 3
This gives you a loop over the source array indices, which are mapped to the destination array indices.
int[][] arrayConvt = array[array.length][array[0].length * array[0][0].length];
for (int i = 0; i < array.length; ++i) {
for (int j = 0; j < array[i].length; ++j) {
for (int k = 0; k < array[i][j].length; ++j) {
arrayConvt[j + (i/3)*3][k + (i%3)*3] = array[i][j][k];
}
}
}
Calculate Source Indices
You can take the above expressions for u and v and rewrite them so i, j and k are in terms of u and v. You could also try starting from u and v and examine how i, j and k might come from them. Let's do this, but by a different route: examine the entries in the sample array2d, since i, j and k can be read directly from it (not an accident; by encoding coordinates into the original array and figuring out where each element should get mapped to, the overall mapping is, in effect, created. You could even use this as the basis for the mapping function: loop over the elements of the coordinate array, and use the values & indices to copy from the source to the destination).
k we see increasing left-to-right only (along v), though it wraps around. This is simply v % 3. j increases top-to-bottom (along u) and also wraps around. Thus j = u % 3.
i varies with both u and v. It also occurs in groups of 3 along both axes before changing, so we're looking for something involving u / 3 and v / 3. Lastly, it varies faster along v and jumps by 3 along u, so i = (u / 3) * 3 + (v / 3).
You can loop over the destination array indices, and map the source array indices.
int[][] arrayConvt = array[array.length][array[0].length * array[0][0].length];
for (int u = 0; i < arrayConvt.length; ++i) {
for (int v = 0; j < arrayConvt[i].length; ++j) {
arrayConvt[u][v] = array[ (u / 3) * 3 + (v / 3) ][u % 3][v % 3];
}
}
Beyond the Problem
There's another approach that, once spotted, is even easier to work with. Hidden in the 3D array is a hypercube: array can be viewed as a projection of a 4D array into 3 dimensions. You can realize this in various (equivalent) ways:
envisioning array as 9x3x3, broken into three cubes, you get one fairly common visualization of a projected discrete hypercube (the same as a 3x3x3 discrete cube projected into 2D is 3 3x3 squares).
An MxN array can be represented as an array of 1 lower rank of size M*N by mapping [i][j] to i*N+j (this is how multidimensional arrays are implemented in languages that use contiguous memory for such arrays). Under this mapping, a T[M][N] is equivalent to T[M*N]. Looking at the indices, note that i can be refactored as i = i_0 * 3 + i_1, where i_0 and i_1 range from 0 through 2. Thus, array[9][3][3] is equivalent to a multidimensional array array4d[3][3][3][3].
From this vantage, the problem is a simple reshaping from a rank 4 cube to a rank 2 cube; the main work is:
figuring out the index order from the source
identifying which indices of the destination to map to
With indices h, i, j and k, we have the index expression array[h*3+i][j][k] (note: i is the 3rd dimension, or depth, and h is the 4th, or duration). When mapping, the last index of array remains the last of arrayConvt (the 1st dimension). After completing a loop over k, we advance along the outermost array; in particular, the 3rd dimension, i (the 4th is also along the outermost array but jumps from cube to cube). After copying a square (with dimensions width x depth), we continue with a cube, travelling along its height, or j axis. Lastly, we check that the travel direction corresponds to the remaining axis: after finishing a cube, we go to the next cube, which is indeed along h. This gives a an index order (minor to major) of k, i, j, h.
The formulae for u and v come straight from the T[M][N] to T[M*N] conversion. Each index of arrayConvt uses two indices from the hypercube, in the previously determined index order: that's h and j for u, and i and k for v. Thus, u = h * 3 + j and v = i * 3 + k.
int M = 3,
N = 3,
P = 3,
Q = 3;
for (int h = 0; h < M; ++h) {
for (int i = 0; i < N; ++i) {
for (int j = 0; j < P; ++j) {
for (int k = 0; k < Q; ++j) {
arrayConvt[h * 3 + j][i * 3 + k] = array[h * 3 + i][j][k];
}
}
}
}
Note the index expressions here can be converted to the ones used earlier. You could use this to write a non-nested loop over 0..80 that reshapes array, but it wouldn't be as readable. You can also use this approach to reshape the hypercube to any compatible shape you want.
Related
I am trying to solve Project Euler problem 18. I have created an array for each row (starting from the bottom), and then an array of those arrays. I created a recursive method that starts from the bottom row, and looks ahead three rows to find the best path.
I created minimum and maximum methods to make sure that the index of my arrays could not go below zero, or above the length minus one.
/**
* A method that sets a minimum limit for an integer
* #param a The number
* #param b The lowest value it can go
* #return a
*/
public static int min(int a, int b) {
if (a<b) {
a=b;
}
return a;
}
/**
* Sets the maximum limit for an int
* #param a the number
* #param b The highest a number can go
* #return a
*/
public static int max(int a, int b) {
if(a>b) {
a=b;
}
return a;
}
Then I used these methods when calculating all possible paths in the next three rows.
I got the Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 11 error on this line of code:
eighthPoss = array[x+2][max(i, array[x].length-1)] + array[x+1][max(i, array[x].length-1)] + array[x][max(i, array[x].length-1)];
Where x is the current row, and i is the current position on the row.
I have if statements for when x+2 and x+1 are more than the amount of rows (When we are on the second to last, or last row of the triangle). I am genuinely confused how anything on this line of code is out of bounds as I have minimum and maximum values on each of them to make sure they don't go out of the range. I ran print statements and the last numbers the loops ran through before the error were x=1, i=10.
Below are my arrays. (I did not include the top row, since it is only one number.)
int[] row1 = {04, 62, 98, 27, 23, 9, 70, 98, 73, 93, 38, 53, 60, 04, 23};
int[] row2 = {63, 66, 04, 68, 89, 53, 67, 30, 73, 16, 69, 87, 40, 31};
int[] row3 = {91, 71, 52, 38, 17, 14, 91, 43, 58, 50, 27, 29, 48};
int[] row4 = {70, 11, 33 ,28, 77, 73, 17, 78, 39, 68, 17, 57};
int[] row5 = {53, 71, 44, 65, 25, 43, 91, 52, 97, 51, 14};
int[] row6 = {41, 48, 72, 33, 47, 32, 37, 16, 94, 29};
int[] row7 = {41, 41, 26, 56, 83, 40, 80, 70, 33};
int[] row8 = {99, 65, 4, 28, 6, 16, 70, 92};
int[] row9 = {88, 2, 77, 73, 7, 63, 67};
int[] row10 = {19, 1, 23, 75, 3, 34};
int[] row11 = {20, 4, 82, 47, 65};
int[] row12 = {18, 35, 87, 10};
int[] row13 = {17, 47, 82};
int[] row14 = {95, 64};
int[][] rows = {row1, row2, row3, row4, row5, row6, row7, row8, row9, row10, row11, row12,
row13, row14};
Any help you could give me would be greatly appreciated.
Make sure that your x+2 isn't going out of bounds as it seems you're only checking to see if i is going out of bounds. (You may be checking for it somewhere else but you didn't provide that code).
Bonus clamp method that I personally use instead of individual max and min methods (since they're built into Java).
public static int clamp(int a, int min, int max) {
return Math.max(min, Math.min(max, a));
}
The following is my implementation of Selection Sort:
package algorithm.selectionsort;
public class SelectionSort {
public static void main(String[] args) {
int[] myArray = selectionSort(new int[] { 9, 9, 9, 8, 7, 73, 32, 109, 1100, 432, 321, 0 });
for (int element : myArray) {
System.out.print("" + element + " ");
}
}
public static int[] selectionSort(int[] a) {
int min;
for (int i = 0; i < a.length - 1; i++) {
min = i;
for (int j = i + 1; j < a.length; j++) {
if (a[j] < a[min]) {
min = j;
int temp = a[i];
a[i] = a[min];
a[min] = temp;
}
}
}
return a;
}
}
I noticed that my instructor codes it slightly differently:
public static int[] selectionSort(int[] a) {
int min;
for (int i = 0; i < a.length - 1; i++) {
min = i;
for (int j = i + 1; j < a.length; j++) {
if (a[j] < a[min]) {
min = j;
}
}
int temp = a[i];
a[i] = a[min];
a[min] = temp;
}
return a;
}
Both implementations work. I'm curious as to what the difference here is. Is it efficiency?
The difference between your instructor's and yours is that he iterate through the array and for each element, search for the minimum, then perform a swap with the element after the wall index.
For yours, you iterate through the array and for each element, while searching for the minimum, if current value is < then the current tentative min, perform a swap with the element after the wall index.
So instead of swapping n times, you could possible swap n*n times for worst case:
Your swap for just one pass (worst case):
100, 90, 88, 70, 55, 43, 32, 28, 19, 10
90, 100, 88, 70, 55, 43, 32, 28, 19, 10
88, 100, 90, 70, 55, 43, 32, 28, 19, 10
70, 100, 90, 88, 55, 43, 32, 28, 19, 10
55, 100, 90, 88, 70, 43, 32, 28, 19, 10
43, 100, 90, 88, 70, 55, 32, 28, 19, 10
32, 100, 90, 88, 70, 55, 43, 28, 19, 10
28, 100, 90, 88, 70, 55, 43, 32, 19, 10
19, 100, 90, 88, 70, 55, 43, 32, 28, 10
10, 100, 90, 88, 70, 55, 43, 32, 28, 19
Your instructor's swap for just one pass (worst case):
100, 90, 88, 70, 55, 43, 32, 28, 19, 10
10, 90, 88, 70, 55, 43, 32, 28, 19, 100
In essence, you swap the values while in the midst of searching for the min. The "min" you swapped may not be the lowest value in the array.
ofcouse your instructor's code is more efficiency and more elegant.
What is Selection Sort?
The algorithm divides the input list into two parts: the sublist of items already sorted, which is built up from left to right at the front (left) of the list, and the sublist of items remaining to be sorted that occupy the rest of the list. Initially, the sorted sublist is empty and the unsorted sublist is the entire input list. The algorithm proceeds by finding the smallest (or largest, depending on sorting order) element in the unsorted sublist, exchanging (swapping) it with the leftmost unsorted element (putting it in sorted order), and moving the sublist boundaries one element to the right.
If the length of the list to be sorted is n, then just n times of exchange should be done, but in your code, it's n*(n-1)*(n-2)....
Trying to make a simple encryption/decryption to use it in a simple communication protocol.
It seems I can't make my decrypt method to work or maybe is the encryption method, the output text is not the original one.
What am I doing wrong?
String s1 = encrypt("Hello World!");
String s2 = decrypt(s1);
public static String encrypt(String decStr) {
byte[] key = new byte[]{
92, -33, 70, 90, 42, -22, -76, 38,
37, 109, 26, -113, 125, 105, 66, 81,
17, 22, 21, -30, 87, -124, -85, 58,
40, -116, -100, 28, 37, 127, 51, 36
};
byte[] encBytes = decStr.getBytes();
int n = encBytes.length + 5;
int k = key[encBytes.length % key.length] & 255;
for (int i = 0; i < encBytes.length; i++) {
encBytes[i] ^= key[(n + i) % key.length];
encBytes[i] ^= key[(k + i) % key.length];
}
return new BigInteger(encBytes).toString(36);
}
public static String decrypt(String encStr) {
byte[] key = new byte[]{
92, -33, 70, 90, 42, -22, -76, 38,
37, 109, 26, -113, 125, 105, 66, 81,
17, 22, 21, -30, 87, -124, -85, 58,
40, -116, -100, 28, 37, 127, 51, 36
};
byte[] encBytes = new BigInteger(encStr, 36).toByteArray();
byte[] decBytes = Arrays.copyOfRange(encBytes, 1, encBytes.length);
int n = decBytes.length + 5;
int k = key[decBytes.length % key.length] & 255;
for (int i = 0; i < decBytes.length; i++) {
decBytes[i] ^= key[(n + i) % key.length];
decBytes[i] ^= key[(k + i) % key.length];
}
return new String(decBytes);
}
byte[] decBytes = Arrays.copyOfRange(encBytes, 1, encBytes.length);
You are starting from the second character. Change the 1 to a 0
byte[] decBytes = Arrays.copyOfRange(encBytes, 0, encBytes.length);
Copies the specified range of the specified array into a new array. The initial index of the range (from) must lie between zero and original.length, inclusive. The value at original[from] is placed into the initial element of the copy (unless from == original.length or from == to). Values from subsequent elements in the original array are placed into subsequent elements in the copy. The final index of the range (to), which must be greater than or equal to from, may be greater than original.length, in which case (byte)0 is placed in all elements of the copy whose index is greater than or equal to original.length - from. The length of the returned array will be to - from.
https://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html#copyOfRange(byte[],%20int,%20int)
Also, you are creating a new byte array and then immediately copying it into a second array but never use the original. It seems there is no need to perform this copy in the first place
Test:
Hello World!
zxj9kxukhtsdmoll41
Hello World!
i got below mentioned error when run code:
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 1, Size: 0
at java.util.LinkedList.checkPositionIndex(Unknown Source)
at java.util.LinkedList.addAll(Unknown Source)
at Collection.Dynamycmaasiv.Collecktionaddlist.main(Collecktionaddlist.java:36)
code
public static void main(String[] args) {
LinkedList<Integer> num = new LinkedList<Integer>();
LinkedList<Integer> numodd = new LinkedList<Integer>();
LinkedList<Integer> numeven = new LinkedList<Integer>();
LinkedList<Integer> sumoffevenandodd = new LinkedList<Integer>();// help
// me
// to
// solve
for (double i = 0; i < 50; i++) {
num.add((int) i);
if (i % 2 == 0) {
numeven.add((int) i);
} else {
numodd.add((int) i);
}
}
System.out.println(num);
System.out.println("-----------------");
System.out.println(numodd);
System.out.println("-----------------");
System.out.println(numeven);
for (int i =0; i<numeven.size(); i++){
sumoffevenandodd.addAll(numeven.get(i)+ numodd.get(i), null);
}
System.out.println(sumoffevenandodd);
}
}
addAll() is not about adding up numbers. It is about adding all the elements of the method parameter to the collection itself.
So, you need to loop, like
int sum = 0;
for (Integer numberFromList : numeven) {
sum = sum + numberFromList;
Or, if you have Java8, you can use streams:
int sumEven = numeven.stream().sum();
Sum, done.
And for the record: the real lesson to be learned here: read the javadoc. Don't assume that method called addAll() does what you suppose it does. Turn to the javadoc and inform yourself what reality thinks about your assumptions.
But just to be clear; as I got carried away with your question, too.
In your code, if you change
sumoffevenandodd.addAll(numeven.get(i)+ numodd.get(i), null);
to
sumoffevenandodd.add(numeven.get(i)+ numodd.get(i));
it should work, too.
Long story short: if you intended to really have a list with 50 sums within, then my first paragraphs do not really help with your problem.
But it isn't exactly clear what you wanted to do; so I leave my answer as is - to address both possible explanations what is "wrong" in your logic.
if the intention of the question is
num odd
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49]
num even
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48]
sum of odd and even
[1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97]
then
for (int i =0; i< numeven.size(); i++){
sumoffevenandodd.add(numeven.get(i)+ numodd.get(i));
}
Hashtable ht = new Hashtable();
for (int i = 0; i < 100; i++) {
ht.put(i%10, i);
}
Enumeration< Integer> eles = ht.elements();
while(eles.hasMoreElements())
System.out.println(eles.nextElement());
Above code snippet is printing 99, 98,.......90
But I want to print all 100 elements.
How to get a list of numbers like ...
99,89,79,69,...19,9
98,88,78,68....18,8
97,87,77,67....17,7
..
..
91,81,71,61....11,1
Basically all collision list.
You are currently using i % 10 as your hash map key, which only has ten values (0-9). Hence only the last ten values are stored in your map, all the others are overriden.
If you need to store more than one item in each bucket, use a list type as your value. For example:
Hashtable<Integer, List<Integer>> ht = new Hashtable<>();
for (int i = 0; i < 100; i++) {
int key = i % 10;
List<Integer> list = ht.get(key);
if (list == null) {
list = new ArrayList<>();
ht.put(key, list);
}
list.add(i);
}
Enumeration<List<Integer>> eles = ht.elements();
while (eles.hasMoreElements()) {
System.out.println(Arrays.toString(eles.nextElement().toArray()));
}
Output:
[9, 19, 29, 39, 49, 59, 69, 79, 89, 99]
[8, 18, 28, 38, 48, 58, 68, 78, 88, 98]
[7, 17, 27, 37, 47, 57, 67, 77, 87, 97]
[6, 16, 26, 36, 46, 56, 66, 76, 86, 96]
[5, 15, 25, 35, 45, 55, 65, 75, 85, 95]
[4, 14, 24, 34, 44, 54, 64, 74, 84, 94]
[3, 13, 23, 33, 43, 53, 63, 73, 83, 93]
[2, 12, 22, 32, 42, 52, 62, 72, 82, 92]
[1, 11, 21, 31, 41, 51, 61, 71, 81, 91]
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
What you observe in your example is not collision effect. It is normal element replacement.
After your 100 iteration there are only 10 elements in Hashtable.
You use numbers i%10 (0,1,...,9) as keys. So, you have only 10 different keys.
For example: in your for-loop you put 10 values for key=5 (i=5, i=15, i=95) and each put(5, val) replaces old value associated with key=5.
Collision list is different concept.
For each key hashtable computes some hash value and uses this hash to select index in its inner bucket table. Next places {key,value} under that index.
Collision is situation where 2 different keys has computed the same bucket index.
For example:
table index | map.entry
0 | {0, "A"}
1 | {3, "B"}
2 | {2, "A"} -> {4, "C"}
3 | {1, "D"} -> {5, "A} -> {6, "F}
In this example you have hashtable with 4-element inner table.
This hashtable contains 7 element (7 different keys) but:
key 2 and 3 was placed to the same bucket (they have the same index computed upon hash value)
key 1, 5, 6 was placed to the same bucket.
So we can say, there is collision between key=2 and key=3 and between 1,5,6.
In other words keys 2 adn 3 are on the same collision list. The same to keys 1,5,6.
You cannot get such collistion list from Hashtable because it is Hashtable internal implementation marked as private:
/**
* Hashtable bucket collision list entry
*/
private static class Entry<K,V> implements Map.Entry<K,V> {
int hash;
final K key;
V value;
Entry<K,V> next;
protected Entry(int hash, K key, V value, Entry<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
...
public V setValue(V value) {
if (value == null)
throw new NullPointerException();
V oldValue = this.value;
this.value = value;
return oldValue;
}
...
public int hashCode() {
return hash ^ value.hashCode();
}
...
}
And Hashtable have its internal bucket table defined as:
/**
* The hash table data.
*/
private transient Entry<K,V>[] table;
Hope this helps to figure out hashtable behavior.