The tail is replaced instead of append - java

I have a method called public void insertAfterSecondOccurrence(T e1, T e2) that would insert an integer after the second occurrence of another integer. However my problem is that if the integer inserted is before the last integer in the list, the method would just replace the tail with the inserted integer instead of appending it.
Here is the method code :
public void insertAfterSecondOccurrence(T e1, T e2) {
// insert e1 after the second occurence of e2
if(isEmpty()) {
System.out.println("Error the list is empty.");
}
SLLNode<T> p = head;
int count = 0;
for(int i = 0; i < size(); i++) {
if(p.info.equals(e2)) {
count++;
}
p = p.next;
}
if(count <= 1) {
System.out.println("Error there is no sec");
}
SLLNode<T> p2 = head;
SLLNode<T> p3 = head;
SLLNode<T> pred =head;
SLLNode<T> tmp = new SLLNode<T>(e1);
int count2 = 0;
for(int i = 0; i < size(); i++) {
if(p2.info.equals(e2)) {
pred = p2.next;
p3 = p2;
count2++;
}
if(count2 == 2) {
break;
}
p2 = p2.next;
}
pred.next = pred;
pred = pred.next;
p3.next = tmp;
}
I tried replacing the last 3 lines with :
tail.next = tail;
tail = tail.next;
p3.next = tmp;
But it didn't work. Here is an example of how it should be, this is the original array [ 7 5 3 50 7 9 ], after calling the method it should be [ 7 5 3 50 7 30 9 ], what i keep getting is [ 7 5 3 50 7 30 ].
I would appreciate if you give me basic responses this is my first time using the website so I'm not familiar with the terms/slang in this website.

I have changed the last 3 lines with this code :
p3.next = tmp;
tmp.next = pred;
And solved my problem.

Related

Sort the array elements based on the elements frequency in java

I have written code to sort the array in java based on the frequency of the elements in it. I need better code or pseudo code (without collection framework).Please help with links or code.
public class SortByFreq1 {
public static void main(String[] args) {
int arr[] = { 2, 5, 2, 8, 5, 6, 8, 8, 0, -8 };
int nArr[] = new int[arr.length];
Map<Integer,Integer> map = new HashMap<Integer, Integer>();
Map<Integer,Integer> sortmap = new HashMap<Integer, Integer>();
ArrayList<Integer> arrList = new ArrayList<Integer>();
for (int i = 0; i < arr.length; i++) {
arrList.add(arr[i]);
}
Set<Integer> set = new HashSet<Integer>(arrList);
for (Integer i : set) {
map.put(i, Collections.frequency(arrList, i));
}
// System.out.println(map.keySet());
// sort map by value
Set<Entry<Integer,Integer>> valList=map.entrySet();
ArrayList<Entry<Integer, Integer>> tempLst = new ArrayList<Map.Entry<Integer, Integer>>(valList);
Collections.sort(tempLst, new Comparator<Entry<Integer, Integer>>() {
#Override
public int compare(Entry<Integer, Integer> o1, Entry<Integer, Integer> o2) {
return o2.getValue().compareTo(o1.getValue());
}
});
int k = 0;
for (Entry<Integer, Integer> entry : tempLst) {
int no = entry.getKey();
int noOfTimes = entry.getValue();
int i = 0;
while (i < noOfTimes) {
nArr[k++] = no;
i++;
}
}
for (int i = 0; i < nArr.length; i++)
System.out.print(nArr[i] + " ");
}
}
The logic behind it is quite similar to Counting Sort.
ATTENTION: We are NOT to modify the array passed in.
There are two different methods while having almost the same time and space complexity.
Time complexity: max(n, O(klogk));
Space complexity: O(n) - the array to be returned;
k mentioned above is the amount of distinct numbers in the array.
Built-in Collection Method
Using Stream perhaps we can make the process a little bit cleaner though OP is not asking for this:
/**
* 1. count the frequency and sort the entry based on the frequency while using LinkedHashMap to retain the order;
* 2. fill up the new array based on the frequency while traversing the LinkedHashMap;
* #param arr
* #return
*/
private static int[] sortByCounting(int[] arr) {
Map<Integer, Long> countMap = Arrays.stream(arr).boxed()
.collect(Collectors.groupingBy(Integer::intValue, Collectors.counting()))
.entrySet().stream()
.sorted((e1, e2) -> e2.getValue().compareTo(e1.getValue()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldV, newV) -> oldV, LinkedHashMap::new));
int[] newArr = new int[arr.length];
int i = 0;
for (Map.Entry<Integer, Long> entry : countMap.entrySet()) {
Arrays.fill(newArr, i, i += entry.getValue().intValue(), entry.getKey());
}
return newArr;
}
Custom Method
Since we cannot use built-in collection methods, meantime we have to record the count for the number.
Instinctively, we could introduce a custom pair to record the number and its related frequency (or count we could say) as our custom method.
private static int[] sortByPlainCounting(int[] arr) {
if (arr.length < 1) throw new IllegalArgumentException("Array cannot be empty");
MyPair[] pairs = prepareMyPairs(arr);
Arrays.sort(pairs, Comparator.comparing(MyPair::getCount).reversed());
int[] newArr = new int[arr.length];
int i = 0;
for (MyPair pair : pairs) {
Arrays.fill(newArr, i, i += pair.count, pair.key);
}
return newArr;
}
static class MyPair {
int key;
int count;
public MyPair(int theKey) {
this.key = theKey;
this.count = 1;
}
public void inc() {
this.count++;
}
public int getCount() {
return this.count;
}
}
static MyPair[] prepareMyPairs(int[] arr) {
Integer[] tmpArr = Arrays.stream(arr).boxed().toArray(Integer[]::new);
Arrays.sort(tmpArr, Comparator.reverseOrder());
int count = 1;
int prev = tmpArr[0];
for (int i = 1; i < tmpArr.length; i++) {
if (tmpArr[i] != prev) {
prev = tmpArr[i];
count++;
}
}
MyPair[] pairs = new MyPair[count];
int k = 0;
for (int i = 0; i < tmpArr.length; i++) {
if (pairs[k] == null) {
pairs[k] = new MyPair(tmpArr[i]);
} else {
if (pairs[k].key == tmpArr[i]) {
pairs[k].inc();
} else {
k++; i--;
}
}
}
return pairs;
}
A comparison and demonstration
Make a final comparison, we can prove that:
average time cost of custom is a little bit worse (1.4 times worse) while the worst case is far better (4 times better) than the built-in collection method;
the custom method is correct;
public static void main(String[] args) {
int N = 10_000 + new Random().nextInt(100);
Long start;
List<Long> list0 = new ArrayList<>();
List<Long> list1 = new ArrayList<>();
for (int i = 0; i < 100; ++i) {
int[] arr = RandomGenerator.generateArrays(N, N, N / 10, N / 5, false);
start = System.nanoTime();
int[] arr0 = sortByCounting(arr);
list0.add(System.nanoTime() - start);
start = System.nanoTime();
int[] arr1 = sortByPlainCounting(arr);
list1.add(System.nanoTime() - start);
System.out.println(isFrequencyEqual(arr0, arr1));
}
System.out.println("Collection time cost: " + list0.stream().collect(Collectors.summarizingLong(Long::valueOf)));
System.out.println("Custom time cost: " + list1.stream().collect(Collectors.summarizingLong(Long::valueOf)));
}
private static boolean isFrequencyEqual(int[] arr0, int[] arr1) {
Map<Integer, Long> countMap0 = getCountMap(arr0);
Map<Integer, Long> countMap1 = getCountMap(arr1);
boolean isEqual = countMap0.entrySet().size() == countMap1.entrySet().size();
if (!isEqual) return false;
isEqual = countMap0.values().containsAll(countMap1.values()) &&
countMap1.values().containsAll(countMap0.values());
if (!isEqual) return false;
List<Long> countList0 = countMap0.values().stream().collect(Collectors.toList());
List<Long> countList1 = countMap1.values().stream().collect(Collectors.toList());
for (int i = 0; i < countList0.size(); i++) {
if (countList1.get(i) != countList0.get(i)) return false;
}
return true;
}
private static Map<Integer, Long> getCountMap(int[] arr) {
return Arrays.stream(arr).boxed()
.collect(Collectors.groupingBy(Integer::intValue, Collectors.counting()))
.entrySet().stream()
.sorted((e1, e2) -> e2.getValue().compareTo(e1.getValue()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldV, newV) -> oldV, LinkedHashMap::new));
}
The helper util method:
public static int[] generateArrays(int minSize, int maxSize, int low, int high, boolean isUnique) {
Random random = new Random(System.currentTimeMillis());
int N = random.nextInt(maxSize - minSize + 1) + minSize;
if (isUnique) {
Set<Integer> intSet = new HashSet<>();
while (intSet.size() < N) {
intSet.add(random.nextInt(high - low) + low);
}
return intSet.stream().mapToInt(Integer::intValue).toArray();
} else {
int[] arr = new int[N];
for (int i = 0; i < N; ++i) {
arr[i] = random.nextInt(high - low) + low;
}
return arr;
}
}
And the test output:
Sorted by frequency: true
// ... another 98 same output
Sorted by frequency: true
Collection time cost: LongSummaryStatistics{count=100, sum=273531781, min=466684, average=2735317.810000, max=131741520}
Custom time cost: LongSummaryStatistics{count=100, sum=366417748, min=1733417, average=3664177.480000, max=27617114}
Can be done in O(n) using pigeonhole sort. Pseudo code:
counts = new HashMap<Item, int>(),;
foreach item in elements:
counts[item] += 1;
buckets = new List<Item>[elements.length+1];
foreach item in counts:
buckets[counts[item]].Append(item)
for i from 1 to elements.length:
bucket = buckets[i]; /* edit: looping over i instead over bucket */
for item in bucket:
/* edit: if the out has to preserve the original number of elements
such as [1,5,5,0,1,9,1] will print
9,0,5,5,1,1,1 instead of 9,0,5,1, then the next line
has to be repeated i times*/
System.out.println(item)
edit: The same can be written without collection framework, by implementing a hash table and a linked list:
class Node {
public Node next;
public int value;
};
log2count = Math.ceil(Math.log(elements.length) / Math.log(2));
hashSize = (int) Math.Round(Math.Pow(2, log2count) * 2);
/* countsQuadraticProbing[i] is 0 if the hash entry is empty,
otherwise it contains the frequency of the element in
elementsQuadraticProbing[i].
Note that quadratic probing over a hash table of size 2**k,
and probing of (0.5 i + 0.5 i**2) is guaranteed to find an empty
entry if the hash table is not full.
*/
countsQuadraticProbing = new int[hashSize];
elementsQuadraticProbing = new int[hashSize];
foreach item in elements:
for i from 0 to hashSize-1:
index = (item + (i * (i + 1) / 2)) % hashSize;
if countsQuadraticProbing[index] == 0:
countsQuadraticProbing[index] = 1;
elementsQuadraticProbing[index] = item;
break;
if elementsQuadraticProbing[index] == item:
countsQuadraticProbing[index]++;
break;
buckets = new Node[elements.length+1];
for i from 0 to hashSize-1:
count = countsQuadraticProbing[index];
if count != 0:
Node topNode = new Node();
topNode.next = buckets[count];
topNode.value = elementsQuadraticProbing[i];
buckets[count] = topNode;
/* there are O(N) buckets, total of elements in all buckets O(N),
overall complexity of the nested loop O(N)
*/
for i from 1 to elements.length:
node = buckets[i] /* edit: using i for iteration */
while node != null:
/* edit: if the out has to preserve the original number of elements
such as [1,5,5,0,1,9,1] will print
9,0,5,5,1,1,1 instead of 9,0,5,1, then the next line
has to be repeated i times*/
System.out.println(node.value);
node = node.next;
I'm just curious why couldn't you use the good old bubble sort in the case and just customize a bit the Bubble In worst case scenario the time complexity is going to be O(n*n) and space complexity will be O(3n) :)
Pure arrays implementation is going to be something like:
private static void bubbleSortByOccurrences(int[] arr) {
int[][] counter = new int[2][arr.length];
int counterIndex = -1;
for (int value : arr) {
int idx = 0;
for (; idx <= counterIndex; idx++) {
if (counter[0][idx] == value) {
counter[1][idx]++;
while (idx > 0 && counter[1][idx] > counter[1][idx-1]) {
int temp = counter[1][idx];
counter[0][idx] = counter[0][idx-1];
counter[1][idx] = counter[1][idx-1];
counter[0][idx-1] = value;
counter[1][idx-1] = temp;
idx--;
}
break;
}
}
if (idx > counterIndex) {
counter[0][idx] = value;
counter[1][idx]++;
counterIndex = idx;
}
}
fillArrayBackwards(arr, counter, counterIndex);
}
private static void fillArrayBackwards(int[] buf, int[][] counter, int counterIndex) {
for (int i = counterIndex, j = buf.length - 1; i >=0; i--) {
for (int k = 0; k < counter[1][i]; k++) {
buf[j--] = counter[0][i];
}
}
}
And the same algorithm implemented by using a Bubble class will look something like:
private static void bubbleSortByOccurrences(int[] arr) {
Bubble head = null;
for (int value : arr) {
if (head == null) {
head = new Bubble(value);
} else {
Bubble currentHead = null;
Bubble current = head;
for (; current != null && !(current.getValue() == value); current = current.getTail()) {
currentHead = current;
}
if (current == null) {
current = new Bubble(value);
current.setTail(head);
head = current;
} else {
current.incrementOccurrences();
while (current.getTail() != null && current.getOccurrences() > current.getTail().getOccurrences()) {
Bubble currentTail = current.getTail();
current.setTail(currentTail.getTail());
currentTail.setTail(current);
if (currentHead != null) {
currentHead.setTail(currentTail);
currentHead = currentTail;
} else {
head = currentTail;
}
}
}
}
}
fillArrayBackwards(arr, head);
}
private static void fillArrayBackwards(int[] buf, Bubble head) {
int i = buf.length - 1;
for (Bubble current = head; current != null; current = current.getTail()) {
for (int j = 0; j < current.getOccurrences(); j++) {
buf[i--] = current.getValue();
}
}
}
Where the custom defined bubble is as follows:
class Bubble {
private int value;
private int occurrences;
private Bubble tail;
public Bubble(int value) {
this.value = value;
this.occurrences = 1;
}
public int getValue() {
return value;
}
public int getOccurrences() {
return occurrences;
}
public void incrementOccurrences() {
this.occurrences++;
}
public Bubble getTail() {
return tail;
}
public void setTail(Bubble tail) {
this.tail = tail;
}
}
your solution is better but since am not using any collections it is gonna be huge.
1.sort the list
2. get the frequency of every element
3. create a new arraylist/ array and store the elements that have higher frequency to lower frequency.
sort the list using any sort algorithm
get the frequency
class CountFrequencies
{
// Function to find counts of all elements present in
// arr[0..n-1]. The array elements must be range from
// 1 to n
void findCounts(int arr[], int n)
{
// Traverse all array elements
int i = 0;
while (i < n)
{
// If this element is already processed,
// then nothing to do
if (arr[i] <= 0)
{
i++;
continue;
}
// Find index corresponding to this element
// For example, index for 5 is 4
int elementIndex = arr[i] - 1;
// If the elementIndex has an element that is not
// processed yet, then first store that element
// to arr[i] so that we don't loose anything.
if (arr[elementIndex] > 0)
{
arr[i] = arr[elementIndex];
// After storing arr[elementIndex], change it
// to store initial count of 'arr[i]'
arr[elementIndex] = -1;
}
else
{
// If this is NOT first occurrence of arr[i],
// then increment its count.
arr[elementIndex]--;
// And initialize arr[i] as 0 means the element
// 'i+1' is not seen so far
arr[i] = 0;
i++;
}
}
System.out.println("Below are counts of all elements");
for (int j = 0; j < n; j++)
System.out.println(j+1 + "->" + Math.abs(arr[j]));
}
above code should give you an output:
1 -> 3
2 -> 0
3 -> 2
4 -> 0
5 -> 2
6 -> 0
7 -> 2
8 -> 0
9 -> 2
10 -> 0
11 -> 0
Now you can easily use the array that stored the frequency of every element to create a new array that contains the most frequent elements in the array
Note that the list is sorted so that arr[0] is the frequency of 1 arr[1] is the frequency of 2 and so on. Again The code is not efficient as yours it is better to use the collection framework.
or if you are familiar use binary trees you can add the element into the tree and use inorder traversal !
Hope you find my answer helpful

Construct a tree from a given array

I would like to construct a graph from a given array and root where the node is described below,
static class TreeNode {
private int value;
private ArrayList<TreeNode> children;
public TreeNode(int nodeValue) {
this.value = nodeValue;
this.children = new ArrayList<TreeNode>();
}
public int getValue() {
return this.value;
}
public void addChild(TreeNode child) {
this.children.add(child);
}
public ArrayList<TreeNode> getChildren() {
return this.children;
}
}
An array provided below to construct the graph,
T[0] = 1
T[1] = 2
T[2] = 3
T[3] = 3
T[4] = 2
T[5] = 1
T[6] = 4
Array T describes a network of cities if T[P] = Q and P ≠ Q, then there is a direct road between cities P and Q. If the index of 2 is root, then the graph is provided below,
2 - 3
/ \
1 4
/ | |
0 5 6
Obviously, I can do it manually for the given array,
final int N = 7;
TreeNode[] nodes = new TreeNode[N];
for (int i = 0; i < N; i++) {
nodes[i] = new TreeNode(i);
}
TreeNode root = nodes[2];
root.addChild(nodes[1]);
root.addChild(nodes[3]);
root.addChild(nodes[4]);
nodes[1].addChild(nodes[0]);
nodes[1].addChild(nodes[5]);
nodes[4].addChild(nodes[6]);
How do I construct programmatically when I have given an array and K value? Please help.
After you construct the TreeNode[] array, it's easy:
TreeNode root = null;
for (int i=0; i<T.length; ++i) {
if (T[i] == i) { // if it's a root node
//TODO: Test for multiple root nodes here
root = nodes[i];
} else {
nodes[T[i]].addChild(nodes[i]);
}
}
I would add a private TreeNode parent; object to the TreeNode class, initialize it to null and set it to the parent reference in the addChild method. That's handy to have during debug, even if you don't need it for the first use of this class. Maybe you'll need it later.
Iterate over all nodes,
for each node get the node's value and add the current node to the node at the value.
for (int i = 0; i < N; i++) {
nodes[nodes[i].getValue()].addChild(nodes[i])
}
I write an answer, however, it's not showing all the children. The code is provided below,
public class App {
static class TreeNode {
private int value;
private ArrayList<TreeNode> children;
public TreeNode(int nodeValue) {
this.value = nodeValue;
this.children = new ArrayList<TreeNode>();
}
public int getValue() {
return this.value;
}
public void addChild(TreeNode child) {
this.children.add(child);
}
public ArrayList<TreeNode> getChildren() {
return this.children;
}
}
public static TreeNode buildGraph(int[] T, int K) {
final int N = T.length;
TreeNode[] nodes = new TreeNode[N];
for (int i = 0; i < N; i++) {
nodes[i] = new TreeNode(i);
}
/*
T[0] = 1
T[1] = 2
T[2] = 3
T[3] = 3
T[4] = 2
T[5] = 1
T[6] = 4
2 - 3
/ \
1 4
/ | |
0 5 6
* */
TreeNode root = nodes[K];
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
boolean[] visited = new boolean[N];
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
int index = node.getValue();
visited[index] = true;
// T[3] = 3 is a leaf with no further connection to develop
if (index == T[index]) {
continue;
}
// 2 != 3 for the root node and we havent visited node 3 earlier
if (index != T[index] && !visited[T[index]]) {
node.addChild(nodes[T[index]]);
queue.offer(nodes[T[index]]);
}
int left = 0, right = N - 1;
while (left < index && right > index) {
if (T[left] == index) {
node.addChild(nodes[left]);
queue.offer(nodes[left]);
}
if (T[right] == index) {
node.addChild(nodes[right]);
queue.offer(nodes[right]);
}
left++;
right--;
}
}
return root;
}
public static void main(String[] args) {
int[] T = new int[7];
T[0] = 1;
T[1] = 2;
T[2] = 3;
T[3] = 3;
T[4] = 2;
T[5] = 1;
T[6] = 4;
TreeNode root = buildGraph(T, 2);
System.out.println("The root = " + root.getValue());
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
TreeNode node = queue.poll();
ArrayList<TreeNode> children = node.getChildren();
for (int i = 0; i < children.size(); i++) {
TreeNode child = children.get(i);
queue.offer(child);
System.out.println("Parent "+ node.getValue()+ " has children = "+ child.getValue());
}
}
}
}
At the time I run, I get output like,
The root = 2
Parent 2 has children = 3
Parent 2 has children = 1
Parent 1 has children = 0
Anyone can help me to correct how do I miss the other children?
Update
I write it based on the other answer which seems simpler.
public static TreeNode buildGraph1(int[] T, int K) {
final int N = T.length;
TreeNode[] nodes = new TreeNode[N];
for (int i = 0; i < N; i++) {
nodes[i] = new TreeNode(i);
}
/*
T[children] = parent if the children != K
T[0] = 1
T[1] = 2
T[2] = 3
T[3] = 3
T[4] = 2
T[5] = 1
T[6] = 4
2 - 3
/ \
1 4
/ | |
0 5 6
* */
TreeNode root = nodes[K];
int value = root.getValue();
if (T[K] != K) {
nodes[K].addChild(nodes[T[K]]);
}
for (int i = 0; i < T.length; ++i) {
if (K == i) {
continue;
}
if (T[i] != i) {
nodes[T[i]].addChild(nodes[i]);
}
}
return root;
}
The output is provided below:
The root = 2
Parent 2 has children = 3
Parent 2 has children = 1
Parent 2 has children = 4
Parent 1 has children = 0
Parent 1 has children = 5
Parent 4 has children = 6

Why doesn't Dijkstra's algorithm work as it should for given graph?

I have the following code, Dijkstra's algorithm, that I made using Wikipedia's article on the algorithm.
For the given graph (see image) and starting node (1), it returns 5 as distance to node (4), which is obviously false. However, when going from node (4), it returns 4 as distance to (1), which is correct. What is wrong in my code?
//source = starting point, adj[] = adjacency list
private static int dijkstra (int source, ArrayList<Road>[] adj) {
HashSet<Integer> vertices = new HashSet<>();
int[] dist = new int[adj.length];
int[] prev = new int[adj.length];
for (int i = 0; i < adj.length; i++) {
dist[i] = Integer.MAX_VALUE;
prev[i] = Integer.MAX_VALUE;
vertices.add(i);
}
dist[source] = 0;
while (!vertices.isEmpty()) {
int current = Integer.MAX_VALUE;
for (int v: vertices) {
if (dist[v] < current) {
current = v;
}
}
vertices.remove(current);
for (Road v: adj[current]) {
int alt = dist[current] + v.distance;
if (alt < dist[v.end]) {
dist[v.end] = alt;
prev[v.end] = current;
}
}
}
}
class Road {
int end;
int distance;
}
//This loop builds adjacency list from input such as "1 3 2", where 1 represents
// starting node, 3 represents end node and 2 represents weight of that edge.
//start and end values are decremented in order to be 0-indexed
for (int i = 0; i < M; i++) {
int start = in.nextInt() - 1;
int end = in.nextInt() - 1 ;
int dist = in.nextInt();
adj[start].add(new Road(end, dist));
adj[end].add(new Road(start, dist));
}
This piece of code is causing the error:
int current = Integer.MAX_VALUE;
for (int v: vertices) {
if (dist[v] < current) {
current = v;
}
}
I assume it's supposed to search the unvisited node that has the shortest path from the start-vertex. But this should look rather like this:
int currentPathLen = Integer.MAX_VALUE, current = -1;
for (int v: vertices) {
if (dist[v] < currentPathLen) {
current = v;
currentPathLen = dist[current];
}
}

Generate an array containing unique Random ints, check for duplicates

This is an assignment for school that I am really close to completing, but I don't have it exactly. I am supposed to generate an array of integer Nodes with 100 random numbers without duplicates by checking for duplicates.
I'm not allowed to use a Set.
I'm not allowed to just shuffle an array of numbers 1-1000.
Here is the code I have in my client class so far but it still creates duplicates:
for (int i = 0; i < SIZE; i++) {
int j = (int)(Math.random()*1999);
//put a random number in the first index.
if (i == 0) {
Node newNode = new Node(j);
nodeArray[i] = newNode;
}
for (int k = 0; k < i; k++) {
if (nodeArray[k].getInt() == j) {
j = (int)(Math.random()*1999);
break;
} else {
Node newNode = new Node(j);
nodeArray[i] = newNode;
}
}
}
The way i would do this would be to use a List to store all the random numbers in. Then when you generate a number you can check if it already exists in the list, and get another number (this is done via recursion, or a while loop). You keep going with this until your list is full. Then go through the list creating the Nodes for your array.
List<Integer> numbers = new ArrayList<Integer>(SIZE);
for (int i = 0;i<SIZE; i++) {
addUniqueRandomNumber(numbers, SIZE*2);
}
for (int i =0;i<numbers.size; i++) {
Node newNode = new Node(numbers.get(i));
nodeArray[i] = newNode;
}
The addUniqueRandomNumber method:
public static void addUniqueRandomNumber(List<Integer> numbers, int range) {
int j = (int)(Math.random()*range);
if (numbers.contains(j)) {
addUniqueRandomNumber(numbers, range);
} else {
numbers.add(j);
}
}
Because when you are assigning a new random if the first random is a duplicate in your second if statement it never checks if that random could be also a duplicate. You need to redo the loop and check if that number is a duplicate as well.
for (int k = 0; k < i; k++) {
if (nodeArray[k].getInt() == j) {
j = (int)(Math.random()*1999); //You must check if this random is also a dup
break;
} else {
Node newNode = new Node(j);
nodeArray[i] = newNode;
}
Here's what I would do:
int i = 0;
while (i < SIZE) {
int j = (int)(Math.random()*1999);
//put a random number in the first index.
if (i == 0) {
Node newNode = new Node(j);
nodeArray[i] = newNode;
i++;
}
for (int k = 0; k < i; k++) {
if (nodeArray[k].getInt() == j) {
//Do nothing
} else {
Node newNode = new Node(j);
nodeArray[i] = newNode;
i++;
}
}
}
Basically only increment i if the number is not duplicate, otherwise go through and try to find another random that is not a duplicate.
Solution algorithm which check after each generated number exist is or no:
int[] nodeArray = new int[100];
int currentIndex = 0;
while(currentIndex < 100) {
int currentValue = (int) (Math.random() * 199);
int i = 0;
while(i < currentIndex) {
if(currentValue == nodeArray[i]) {
break;
}
i++;
}
if(i == currentIndex) {
nodeArray[currentIndex++] = currentValue;
}
}
Then you can sort ant print random numbers
Arrays.sort(nodeArray); // Sort to be easy find duplicates
for (Integer i : nodeArray) {
System.out.print(i + ", ");
}
I suggest to use a helper boolean array to keep track of which numbers were already added to the array. Review this code, it is short and concise:
boolean[] used = new boolean[2000];
int[] randomUniqueIntegers = new int[SIZE];
for (int i = 0; i < SIZE; i++) {
int num = (int) (Math.random() * 1999);
if (!used[num]) {
used[num] = true;
randomUniqueIntegers[i] = num;
} else {
while (used[num]) {
num = (int) (Math.random() * 1999);
if (!used[num]) {
used[num] = true;
randomUniqueIntegers[i] = num;
break;
}
}
}
}
As you see the implementation above doesn't use Set or shuffling. However, you can use the test code below to see it works correctly.
Set<Integer> set = new HashSet<Integer>();
for (int i : randomUniqueIntegers)
set.add(i);
System.out.println(set.size());
You will see that the size of the set is equal to SIZE constant in each run which indicates we have all unique elements in our array.

Invert Elements in ArrayList<Integer> Java

Ok so the point of this method is the invert the elements in an ArrayList of type <Integer>. So if I have the elements:
5
6
7
8
9
10
once I call the method, the position of the elements should be Inverted as such:
10
9
8
7
6
5
This is the method, any advice would be greatly appreciated :).
public void invertElements()
{
for (int i = list.size()-1; i <= -1; i--)
{
int temp = list.get(i);
for(int j = 0; j < list.size()-1; j++)
{
list.set(j, temp);
}
}
}
list is the name of my ArrayList<Integer>.
Update: Just tried this way:
public void invertElements()
{
int index = 0;
for (int i = list.size()-1; i > -1; i--)
{
int temp = list.get(i);
list.set(index, temp);
index++;
if(index == list.size()-1)
{
break;
}
}
}
which gives the output: 10, 9, 8, 9, 10
Could someone explain to me why?
You can take the extremities of the list at each iteration and swap them :
ArrayList<Integer> list = new ArrayList<>(Arrays.asList(1,2,3,4,5,6,7,8,9,10));
for (int i = 0; i < list.size()/2; i++){
int temp = list.get(i);
int temp2 = list.get(list.size()-1-i);
list.set(i, temp2);
list.set(list.size()-1-i, temp);
}
for(Integer i : list)
System.out.print(i+"-");
Gives the output :
10-9-8-7-6-5-4-3-2-1-
At the first iteration : temp = 1 / temp2 = 10 : we swap them
At the second iteration : temp = 2 / temp2 = 9 : we swap them
And we loop until we go through all the elem of the list which is the size of the list divided by 2.
Solution is
public void invertElems(List<Integer> list) {
for (int i = 0; i < list.size() / 2; ++i) { // we only need iterating half of the size of list
int elem = list.get(i); // we store element in additional variable
list.set(i, list.get(list.size() - i - 1)); // we set i-th elementh with i-th element from the back
list.set(list.size() - i - 1, elem);
}
}
Linear time. Feel free to ask questions.

Categories