I have a project in which i have to implement a weighted quick-union with path compression algorithm.After seeing a number of others source code,i ended up in this:
public class UnionFind {
private int[] parent;
private int[] size;
private int maxItemCount; // maximum number of items from {0,1,...,N-1}
private int numItems; // number of items created
UnionFind(int N) {
this.N = N;
this.K = 0;
parent = new int[N];
size = new int[N];
for (int i = 0; i < N; i++) {
parent[i] = -1;
size[i] = 0;
}
}
void makeSet(int v) {
if (parent[v] != -1) return; // item v already belongs in a set
parent[v] = v;
size[v] = 1;
K++;
}
int find(int v) {
if (v == parent[v]) {
return v;
}
return parent[v] = find(parent[v]);
}
void unite(int v, int u) {
int x=find(v);
int y=find(u);
if(x!=y) {
parent[x]=y;
}
}
int setCount() {
int item=0;
for(int i=0;i<parent.length;i++) {
if(i==parent[i]) {
item++;
}
}
return item; // change appropriately
}
int itemCount() {
return K;
}
The task which has been assigned to me is to complete properly the following methods :
int find(int v)
void unite(int v,int u)
setCount(int v)
Well,the algorithm seems to be slow and i can't find a suitable solution.
Here are some issues:
The size information is not used, yet that information is crucial in keeping the desired performance. Most importantly, in unite:
size should be kept updated: the united set will have as many members as the two given sets had
size should determine which of the two root nodes should be the root of the united set, as this will keep the trees balanced
setCount has O(n) time complexity. It could give the information in O(1) time if you would keep track of that number in a member variable. I'd call it numSets. If setCount() is called a lot, this change will have a positive effect.
Not a problem, but naming variables as N and K is not helping to make the code readable. Why not give names that actually tell what they are, so you don't need to accompany their definitions with a comment to give that explanation?
Here is your code with those adaptations:
public class UnionFind {
private int[] parent;
private int[] size;
private int maxItemCount;
private int numItems;
private int numSets;
UnionFind(int maxItemCount) {
this.maxItemCount = maxItemCount;
numItems = 0;
numSets = 0;
parent = new int[maxItemCount];
size = new int[maxItemCount];
for (int i = 0; i < maxItemCount; i++) {
parent[i] = -1;
size[i] = 0;
}
}
void makeSet(int v) {
if (parent[v] != -1) return; // item v already belongs in a set
parent[v] = v;
size[v] = 1;
numItems++;
numSets++; // Keep track of number of sets
}
int find(int v) {
if (v == parent[v]) {
return v;
}
return parent[v] = find(parent[v]);
}
void unite(int v, int u) {
int x = find(v);
int y = find(u);
if (x != y) {
numSets--; // A union decreases the set count
// Determine which node becomes the root
if (size[x] < size[y]) {
parent[x] = y;
size[y] += size[x]; // Adapt size
} else {
parent[y] = x;
size[x] += size[y]; // Adapt size
}
}
}
int setCount() {
return numSets; // Kept track of it
}
int itemCount() {
return numItems;
}
}
Related
I'm currently enrolled in the Princeton Algorithms course (Part 1) and it talks about an improvement to the quick-union algorithm by maintaining an extra array sz[i] to count the number of objects in the tree rooted i, but it doesn't show how to do that.
Where and how is that counter supposed to be implemented? I've tried doing it in the root method, but I realized it wouldn't count the children of a given object.
This is the unaltered code given in the course:
public class QuickUnionUF {
private int[] id;
public QuickUnionUF(int N) {
id = new int[N];
for (int i = 0; i < N; i++) id[i] = i;
}
private int root(int i) {
while (i != id[i]) i = id[i];
return i;
}
public boolean connected(int p, int q) {
return root(p) == root(q);
}
public void union(int p, int q) {
int i = root(p);
int j = root(q);
id[i] = j;
}
}
To perform weighted union, you need to know weight of every tree, so make parallel array wt[], where wt[k] contains size of tree with root k. Initial weigths are 1.
Glue smaller tree to the root of larger tree and update weight
public void union(int p, int q) {
int i = root(p);
int j = root(q);
if wt[i] < wt[j] {
id[i] = j;
wt[j] += wt[i]
}
else {similar for j->i}
}
Initialization
public class QuickUnionUF {
private int[] id;
private int[] wt;
public QuickUnionUF(int N) {
id = new int[N];
wt = new int[N];
for (int i = 0; i < N; i++) {
id[i] = i;
wt[i] = 1;
}
}
I attempted to follow this pseudocode on wikipedia https://en.wikipedia.org/wiki/Maze_generation_algorithmRandomized_Prim's_algorithm
but my code just generates a full grid. I seem to be missing something in my understanding of what the algorithm does. Can someone help explain what I'm doing wrong?
I've looked at a few sources but I can't wrap my head around it
public class MazeGen {
private int dimension, nodeCounter;
private Node[][] nodes;
private List<Edge> walls;
public static void main(String[] args) {
MazeGen g = new MazeGen(20);
g.generate();
g.printMaze();
}
private void generate() {
pickCell();
generateMaze();
}
private void generateMaze() {
while (!walls.isEmpty()) {
int v;
Edge wall = walls.get(ThreadLocalRandom.current().nextInt(walls.size()));
if ((!wall.nodes[0].visited && wall.nodes[1].visited)
|| (wall.nodes[0].visited && !wall.nodes[1].visited)) {
if (!wall.nodes[0].visited)
v = 0;
else
v = 1;
includeNode(wall.nodes[v]);
wall.nodes[Math.abs(v - 1)].visited = true;
}
walls.remove(wall);
}
}
private void pickCell() {
int i = ThreadLocalRandom.current().nextInt(dimension);
int j = ThreadLocalRandom.current().nextInt(dimension);
includeNode(nodes[i][j]);
}
private void includeNode(Node node) {
node.visited = true;
node.partOfMaze = true;
walls.addAll(node.edges);
}
public void printMaze() {
for (int i = 0; i < dimension; i++) {
System.out.println();
for (int j = 0; j < dimension; j++) {
if (nodes[i][j].partOfMaze) {
System.out.print(".");
} else
System.out.print("p");
}
}
}
public MazeGen(int n) {
nodes = new Node[n][n];
walls = new ArrayList<Edge>();
dimension = n;
createNodes();
connectAdjacents();
}
private void connectAdjacents() {
for (int i = 0; i < dimension; i++) {
for (int j = 0; j < dimension; j++) {
verifyConnection(i, j, i, j + 1);
verifyConnection(i, j, i + 1, j);
}
}
}
private void verifyConnection(int i, int j, int arg1, int arg2) {
if (arg1 < dimension && arg2 < dimension)
connect(i, j, arg1, arg2);
}
private void createNodes() {
for (int i = 0; i < dimension; i++) {
for (int j = 0; j < dimension; j++) {
nodes[i][j] = new Node();
}
}
}
private void connect(int row, int col, int row2, int col2) {
nodes[row][col].edges.add(new Edge(nodes[row][col], nodes[row2][col2]));
nodes[row2][col2].edges.add(new Edge(nodes[row][col], nodes[row2][col2]));
}
private class Node {
boolean visited, partOfMaze;
int number;
List<Edge> edges;
Node() {
number = nodeCounter++;
edges = new ArrayList<Edge>();
}
#Override
public String toString() {
return String.valueOf(number);
}
}
private class Edge {
Node[] nodes;
Edge(Node n, Node n2) {
nodes = new Node[2];
nodes[0] = n;
nodes[1] = n2;
}
#Override
public String toString() {
return nodes[0] + "-" + nodes[1];
}
}
I think that your algorithm is correct but you don't keep the correct output.
All the nodes should be part of the maze. The walls that should be part of the maze are the walls that connect two visited nodes when you proccess them.
make another array of output walls, and set the values in the generateMaze method.
private void generateMaze() {
while (!walls.isEmpty()) {
int v;
Edge wall = walls.get(ThreadLocalRandom.current().nextInt(walls.size()));
if ((!wall.nodes[0].visited && wall.nodes[1].visited)
|| (wall.nodes[0].visited && !wall.nodes[1].visited)) {
if (!wall.nodes[0].visited)
v = 0;
else
v = 1;
includeNode(wall.nodes[v]);
wall.nodes[Math.abs(v - 1)].visited = true;
/////////////////////////////////////
// remove this wall from the output walls
/////////////////////////////////////
} else {
////////////////////////////////
// add this wall to the output walls
////////////////////////////////
}
walls.remove(wall);
}
}
Forget Wikipedia, they censor free speech and manipulate information, especially in political and social areas. For that reason I also deleted all my additions to the Wikipedia page on "maze generation" (see page history).
The idea of "Prim's" MST algorithm is to maintain a "cut" (a set of edges) between disconnected subgraphs and always select the cheapest edge to connect these subgraphs. Visited vertices are marked to avoid generating cycles.
This can be used for maze generation by using edge random weights in a full grid graph or by starting with an empty grid graph and adding randomly weighted edges on the fly.
See my GitHub repository on maze generation for details:
https://github.com/armin-reichert/mazes
https://github.com/armin-reichert/mazes/blob/master/mazes-algorithms/src/main/java/de/amr/maze/alg/mst/PrimMST.java
public void createMaze(int x, int y) {
cut = new PriorityQueue<>();
expand(grid.cell(x, y));
while (!cut.isEmpty()) {
WeightedEdge<Integer> minEdge = cut.poll();
int u = minEdge.either(), v = minEdge.other();
if (isCellUnvisited(u) || isCellUnvisited(v)) {
grid.addEdge(u, v);
expand(isCellUnvisited(u) ? u : v);
}
}
}
private void expand(int cell) {
grid.set(cell, COMPLETED);
grid.neighbors(cell).filter(this::isCellUnvisited).forEach(neighbor -> {
cut.add(new WeightedEdge<>(cell, neighbor, rnd.nextInt()));
});
}
I am attempting to build my own implementation of a hash table in Java in order to gain a better grasp on how hashing works. I am using separate chaining and growing the table and rehashing everything when the load gets over 75% or I have a single chain over 20 in length. I'm hashing strings. I've tried everything I can think of but when I attempt to build the table it runs for a few seconds and then throws a StackOverflowError in my grow method.
Here is the code for the actual HashTable this include the arrayList for the actual table and some ints to keep track of the longest chain the number of collisions and the size. It also includes methods to insert, grow (rehash everything in new arrayList), hash a string, and to find a prime number higher than a given number as well the getter/setters.
import java.util.ArrayList;
import java.util.LinkedList;
public class HashTable {
private ArrayList<LinkedList<String>> hashes;
private int collisionCounter; //the total amount of collisions that have occurred
private int longest; //the length collision
private int size;
public HashTable(int size) {
this.hashes = new ArrayList<LinkedList<String>>();
for (int i = 0; i < size; i++) {
hashes.add(new LinkedList<String>());
}
this.collisionCounter = 0;
this.longest = 0;
this.size = size;
}
public int getCollisionCounter() {
return collisionCounter;
}
public int size() {
return this.size;
}
public int getLongest() {
return this.longest;
}
//grows array to a new size
public void grow(int newSize, int numElements) {
ArrayList<LinkedList<String>> oldHashes = new ArrayList<LinkedList<String>>(this.hashes);
this.hashes = new ArrayList<LinkedList<String>>();
this.collisionCounter = 0;
this.longest = 0;
this.size = newSize;
for (int i = 0; i < this.size; i++) {
hashes.add(new LinkedList<String>());
}
for (int i = 0; i < oldHashes.size(); i++) {
LinkedList<String> currentList = oldHashes.get(i);
for (int q = 0; q < currentList.size(); q++) {
this.insert(currentList.get(q));
}
}
if (this.longest > 20 || this.load(numElements) > .75) {
newSize = newSize + 20;
newSize = this.findPrime(newSize);
this.grow(newSize, numElements);
}
}
//inserts into hashtable keeps track of collisions and the longest chain
public void insert(String element) {
int index = this.hash(element);
this.hashes.get(index).add(element);
if (index < this.size) {
if (this.hashes.get(index).size() > 1) {
this.collisionCounter++;
if (this.hashes.size() > this.longest) {
this.longest++;
}
}
}
}
//finds the first prime number that is larger that the starting number or the original number if that is prime
//if used to find a new table size the int in the parameters will need to be incremented
public int findPrime(int startInt) {
int newNum = startInt++;
boolean isFound = false;
while (!isFound) {
boolean isPrime = true;
int divisor = 2;
while (isPrime && divisor < newNum / 2) {
if (newNum % divisor == 0) {
isPrime = false;
} else {
divisor++;
}
}
if (isPrime) {
isFound = true;
} else {
newNum++;
}
}
return newNum;
}
public double load(int numElements) {
return (numElements + 0.0) / (this.size + 0.0); //int division may be a problem
}
//helper method for insert and search creates hash value for a word
public int hash(String ele) {
char[] chars = ele.toCharArray();
double hashCode = 0;
for (int i = 0; i < chars.length; i++) {
hashCode += chars[i] * Math.pow(5521, chars.length - i);
}
if (hashCode < 0) {
hashCode = hashCode + this.size;
}
return (int) (hashCode % this.size);
}
//method to search for a word in hashtable finds a string in the hastable return true if found false if not found
public boolean search(String goal) {
int index = this.hash(goal);
LinkedList<String> goalList = this.hashes.get(index);
for (int i = 0; i < goalList.size(); i++) {
if (goalList.get(i).equals(goal)) {
return true;
}
}
return false;
}
}
Here is the code for the method that actually builds the table it takes an arrayList of all the words and inserts them into the array (hashing them as it goes) and checks the load/collision length and grows it if needed.
public static HashTable createHash(ArrayList<String> words) {
int initSize = findPrime(words.size());
HashTable newHash = new HashTable(initSize);
for (int i = 0; i < words.size(); i++) {
newHash.insert(words.get(i));
if (newHash.load(i) > .75 || newHash.getLongest() > 20) {
int size = newHash.size();
size = size + 25;
int newSize = findPrime(size);
newHash.grow(newSize, i);
}
}
return newHash;
}
Sorry this is a lot of code to sort through but I cannot figure out what I am doing wrong here and don't know a way to condense it down. Any help is really appreciated!
In your insert method you should have the following instead for keeping track of the longest chain
if(this.hashes.get(index).size() > this.longest) {
this.longest = this.hashes.get(index).size();
}
that explains why it runs for a few seconds and then hits a StackOverflowError, you are recursing infinitely because the value of longest isn't changing (since this.hashes.size() won't change)
So far I have tried to create the method below, but when I run it, the new array leaves zeros for the empty spaces. If a find all method is created to work with this how can it be implemented with a binary search instead of a linear search
package bp;
import java.util.Arrays;
public class SortedList implements IUnsortedList {
/**
* The max size of the List.
*/
public static final int MAX_SIZE = 10000;
/**
* The max value of each occurence.
*/
public static final int MAX_VALUE = 10;
/**
* Flag for the amount of items on the list.
*/
private int sizeOfList = 0;
/**
* Variable to define true or false for duplicates.
*/
private boolean duplicatesAllowed = true;
/**
* Array saves the occurences in the list.
*/
private final int[] listItems = new int[MAX_SIZE];
/**
* Variable for the value to find or delete.
*/
private int searchKey;
/**
* Variable for counter in a loop.
*/
private int f;
#Override
public int getSizeOfList() {
return sizeOfList;
}
#Override
public boolean areDuplicatesAllowed() {
return duplicatesAllowed;
}
#Override
public void setDupliatesAllowed(boolean pDuplicatesAllowed) {
duplicatesAllowed = pDuplicatesAllowed;
}
#Override
public void clear() {
sizeOfList = 0;
}
#Override
public void insert(int pValueToInsert) {
//Loop finds the position of the Item
for (f = 0; f < sizeOfList; f++)
if (listItems[f] > pValueToInsert)
break;
//Loop moves the items after the position up
for (int n = sizeOfList; n > f; n-- )
listItems[n] = listItems[n - 1];
//Insert the Value in the right position
listItems[f] = pValueToInsert;
//Increment List size
sizeOfList++;
}
#Override
public void delete(int pValueToDelete) {
int destroyHAHAHA = find(pValueToDelete);
//If it doesnt find it the item
if (destroyHAHAHA==sizeOfList)
System.out.println("I let you down boss, Can't find "
+ pValueToDelete);
//If it does, kill it with fire
else {
for (int n = destroyHAHAHA; n <sizeOfList; n++)
listItems[n] = listItems[n + 1];
sizeOfList--;
}
}
#Override
public void deleteAll(int pValueToDelete) {
int j = 0;
for(int i = 0; i < listItems.length; i++ )
{
if (listItems[i] != pValueToDelete)
listItems[j++] = listItems[i];
}
int [] newArray = new int[j];
System.arraycopy(listItems, 0, newArray, 0, j );
}
#Override
public void initializeWithRandomData(int pSizeOfList) {
// Loop creates an array with certain number of elements
if (duplicatesAllowed) {
for (int n = 0; n < pSizeOfList; ++n) {
insert(listItems[n] = (int) (Math.random() * MAX_VALUE + 1));
}
} else {
int newvalue=0;
for (int n = 0; n < pSizeOfList; ++n) {
listItems[n] = newvalue++;
++sizeOfList;
}
}
}
#Override
public int find(int pValueToFind) {
searchKey = pValueToFind;
int lowNumber = 0;
int highNumber = sizeOfList - 1;
int result;
while (true) {
result = (lowNumber + highNumber) / 2;
if (listItems[result] == searchKey)
return result;
else if (lowNumber > highNumber)
return sizeOfList;
else {
if (listItems[result] < searchKey)
lowNumber = result + 1;
else
highNumber = result - 1;
}
}
}
#Override
public int[] findAll(int pValueToFind) {
//Array with the location of item
int[] answerArray = new int[sizeOfList];
int searchIndex;
int answerIndex = 0;
for (searchIndex = 0; searchIndex < sizeOfList; searchIndex++) {
if (listItems[searchIndex] == pValueToFind) {
answerArray[answerIndex++] = searchIndex;
}
}
if (answerIndex > 0) {
return Arrays.copyOfRange(answerArray, 0, answerIndex);
} else {
return new int[0];
}
}
#Override
public String toString() {
return Arrays.toString(Arrays.copyOfRange(listItems, 0, sizeOfList));
}
public void bubbleshort(){
int out;
int in;
int middle;
for (out = 0; out < sizeOfList - 1; out++) {
middle = out;
for(in = out +1; in < sizeOfList; in++)
if(listItems[in] < listItems[middle])
middle = in;
selectionSort(out, middle);
}
}
public void selectionSort(int one, int two) {
int temporal = listItems[one];
listItems[one] = listItems[two];
listItems[two] = temporal;
}
}
You can use Common langs ArrayUtils.removeElement() or ArrayUtils.removeAll() method to remove all the elements from the array.
Set contains no duplicates. You can use a Set.
Set<T> mySet = new HashSet<T>(Arrays.asList(someArray));
or
Set<T> mySet = new HashSet<T>();
Collections.addAll(mySet, myArray);
For my current homework, I'm trying to sort my array through a generic class as the user inserts values into its locations. When the size reads as fully loaded, the array class calls in an expansion method that increases the size of the array while retaining its values in proper locations, which I followed from my Professor's note. For some reason, all my values except for location[0] seem to either be misplaced or erased from the array. I'm leaning that the problem originates in the expansion method but I have no idea how to fix this.
For example, the initial size is currently set to 5 but increments by 3 when expansion method is called. The user can input values 1,2,3,4,5 perfectly. But expansion is called when user inputs new value 6 that outputs an array of 1, 6, null, null, null, null. Any further will lead to the error "Exception in thread "main" java.lang.NullPointerException"
Here is my Sorted Array class:
public class SortedArray {
private int size;
private int increment;
private int top;
Comparable[] a;
public SortedArray(int initialSize, int incrementAmount)
{
top = -1;
size = initialSize;
increment = incrementAmount;
a = new Comparable [size];
}
public int appropriatePosition(Comparable value)
{
int hold = top;
if(hold == -1)
{
hold = 0;
}
else
{
for(int i = 0; i <= top; i++)
{
if(value.compareTo(a[i]) > 0)
{
hold = i + 1;
}
}
}
return hold;
}
public Comparable smallest()
{
return a[0];
}
public Comparable largest()
{
return a[top];
}
public void insert(Comparable value)// the method that my driver calls for.
{
int ap = appropriatePosition(value);
//Expansion if full
if(full() == true)
{
expansion();
}
//Shifting numbers to top
for(int i = top; i >= ap ; i--)
{
{
a[i + 1] = a[i];
}
}
a[ap] = value;
top++;
}
public boolean full()
{
if(top == a.length -1)
{
return true;
}
else
{
return false;
}
}
public void expansion()//here's where the expansion begins
{
int newSize = a.length + increment;
Comparable[] tempArray = new Comparable[newSize];
for(int i= 0; i < a.length; i++)
{
tempArray[i]= a[i];
a = tempArray;
}
}
Here's my driver class that calls for the insert method in SortedArray class.
public class IntDriver {
public static void main(String[] args)
{
Scanner keyboard = new Scanner(System.in);
//Creating variables
int data;
boolean check = false;
int choice;
int size = 5;
int increment = 3;
SortedArray b = new SortedArray(size, increment);
//Creating Menu
System.out.println("Please choose through options 1-6.");
System.out.println("1. Insert\n2. Delete\n3. Clear\n4. Smallest\n5. Largest\n6. Exit\n7.Redisplay Menu");
while(check == false)
{
choice = keyboard.nextInt();
switch(choice)
{
case 1:
System.out.println("Type the int data to store in array location.");
data = keyboard.nextInt();
Integer insertObj = new Integer(data);
b.insert(insertObj);
System.out.println("The value " + data + " is inserted");
b.print();
break;
In the expansion method, you're replacing a too soon. The replacement should happen after the for loop:
public void expansion()//here's where the expansion begins
{
int newSize = a.length + increment;
Comparable[] tempArray = new Comparable[newSize];
for(int i= 0; i < a.length; i++)
{
tempArray[i]= a[i];
}
a = tempArray;
}