How would the weighted quick-union Algorithm be implemented? - java

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;
}
}

Related

Weighted Quick-Union with Path Compression algorithm-Union Find

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;
}
}

Find all connected components and their sizes in a graph

I'm trying to find all connected components and their sizes in a graph. I don't know why, but the size is always 0. Maybe something is wrong in the method.
This is the problem that I am trying to solve. https://www.codechef.com/LRNDSA08/problems/FIRESC
public class B {
static void dfs(int s, int v, boolean[] visited, ArrayList<ArrayList<Integer>> adj) {
s++;
visited[v] = true;
for (int u : adj.get(v)) {
if (!visited[u]) {
dfs(s, u, visited, adj);
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
StringBuilder str = new StringBuilder();
int t = sc.nextInt();
for (int xx = 0; xx < t; xx++) {
int n = sc.nextInt();
int m = sc.nextInt();
ArrayList<ArrayList<Integer>> arr = new ArrayList<>();
for (int i = 0; i < n; i++) {
arr.add(new ArrayList<Integer>());
}
boolean[] visited = new boolean[n];
Arrays.fill(visited, false);
for (int i = 0; i < m; i++) {
int a = sc.nextInt();
int b = sc.nextInt();
a--;
b--;
arr.get(a).add(b);
arr.get(b).add(a);
}
long ways = 1;
int groups = 0;
for (int i = 0; i < n; i++) {
if (visited[i])
continue;
int size = 0;
dfs(size, i, visited, arr);
groups++;
ways *= size;
ways %= 1000000007;
}
System.out.println(groups + " " + ways);
}
}
}
You know size is passed as value and not as reference. So it won't get updated after you return from the call. One thing you could do is define a single element array like
int[] size = new int[1];
and modify your dfs like:
static void dfs(int[] s, int v, boolean[] visited, ArrayList<ArrayList<Integer>> adj) {
s[0]++;
visited[v] = true;
for (int u : adj.get(v)) {
if (!visited[u]) {
dfs(s, u, visited, adj);
}
}
}
Then your result will be in size[0] which you can use to update ways like ways *= size[0]
Or you could modify dfs to return size which is a cleaner way to get the size like below:
static int dfs(int v, boolean[] visited, ArrayList<ArrayList<Integer>> adj) {
visited[v] = true;
int sz = 1;
for (int u : adj.get(v)) {
if (!visited[u]) {
sz += dfs(u, visited, adj);
}
}
return sz;
}
And it seems like you have a misconception on how variables in Java work (see). Incrementing an int variable that resides on one lair of the stack would not affect a variable on another stack lair. That's why the size is always 0.
The following solution passes base test on CodeChef:
public class CountComponents {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int testCases = sc.nextInt();
for (int i = 0; i < testCases; i++) {
EmployeeGraph graph = parseGraph(sc);
graph.countComponentsAndComponentSizes();
}
}
public static EmployeeGraph parseGraph(Scanner sc) {
int employeeCount = sc.nextInt();
int connectionsCount = sc.nextInt();
boolean[][] adjacencyMatrix = new boolean[employeeCount][employeeCount];
for (int i = 0; i < connectionsCount; i++) {
int row = sc.nextInt() - 1;
int col = sc.nextInt() - 1;
adjacencyMatrix[row][col] = true;
adjacencyMatrix[col][row] = true;
}
return new EmployeeGraph(adjacencyMatrix);
}
}
class EmployeeGraph {
public static final int BILLION_SEVEN = 1_000_000_007;
private boolean[][] adjacencyMatrix;
public EmployeeGraph(boolean[][] adjacencyMatrix) {
this.adjacencyMatrix = adjacencyMatrix;
}
public void countComponentsAndComponentSizes() {
boolean[] visited = new boolean[adjacencyMatrix.length];
int componentCount = 0;
int waysToChooseCaptain = 1;
for (int row = 0; row < adjacencyMatrix.length; row++) {
if (!visited[row]) {
componentCount++;
waysToChooseCaptain = (waysToChooseCaptain % BILLION_SEVEN) * dfs(visited, row);
}
}
System.out.println(componentCount + " " + waysToChooseCaptain % BILLION_SEVEN);
}
public int dfs(boolean[] visited, int row) {
visited[row] = true; // marking the current employee as visited
int size = 1; // this component consists at least from 1 employee
for (int col = 0; col < adjacencyMatrix.length; col++) {
if (adjacencyMatrix[row][col] && !visited[col]) {
size += dfs(visited, col);
}
}
return size;
}
}

Why does my implementation of randomized Prim's Algorithm in Java just generate a full grid?

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()));
});
}

My program seems to be written perfectly, but stops running and allows user input with no scanner?

first time post here.
I am trying to create a class which compares quick sort, merge sort, bubble sort, and selection sort. I have implemented all of the sort methods and created a random array method which populates a random array with 1000 random ints. However when I run my program my main method stops after the initial welcome message and allows for user input. Any help would be greatly appreciated, I'm sure its some simple mistake I am missing.
import java.util.Random;
public class TestSort {
private static int selectCount;
private static int bubbleCount;
private static int mergeCount;
private static int quickCount;
public static void main(String[] args){
System.out.println("Welcome to the search tester. "
+ "We are going to see which algorithm performs the best out of 20 tests");
int testSelection = 0;
int testBubble = 0;
int testQuick = 0;
int testMerge = 0;
//Check tests
int[] a = new int[1000];
populateArray(a);
int[] select = a;
int[] bubble = a;
int[] quick = a;
int[] merge = a;
testSelection = selectionSort(select);
testBubble = bubbleSort(bubble);
testQuick = quickSort(quick,0,0);
testMerge = mergeSort(merge);
System.out.println("Selection sort number of checks: " + testSelection);
System.out.println("Bubble sort number of checks: " + testBubble);
System.out.println("Quick sort number of checks: " + testQuick);
System.out.println("Merge sort number of checks: " + testMerge);
System.out.println("");
}
public static int[] populateArray(int[] a)
{
Random r = new Random();
a = new int[1000];
for(int i=0; i < a.length; i++)
{
int num = r.nextInt(1000);
a[i] = num;
}
return a;
}
//Sorting methods
public static int selectionSort(int[] a)
{
for (int i = 0; i < a.length; i++)
{
int smallestIndex = i;
for (int j=i; j<a.length; j++)
{
if(a[j]<a[smallestIndex])
{
smallestIndex = j;
}
}
if(smallestIndex != i) //Swap
{
int temp = a[i];
a[i] = a[smallestIndex];
a[smallestIndex] = temp;
selectCount++;
}
}
return selectCount;
}
public static int bubbleSort (int[] a)
{
boolean hasSwapped = true;
while (hasSwapped == true)
{
hasSwapped = true;
for(int i = 0; i<a.length-1; i++)
{
if(a[i] > a[i+1]) //Needs to swap
{
int temp = a[i];
a[i] = a[i+1];
a[i+1] = temp;
hasSwapped = true;
bubbleCount++;
}
}
}
return bubbleCount;
}
public static int mergeSort(int [] a)
{
int size = a.length;
if(size<2)//recursive halting point
{
return 0;
}
int mid = size/2;
int leftSize = mid;
int rightSize = size-mid;
int [] left = new int[leftSize];
int [] right = new int[rightSize];
for(int i = 0; i<mid; i++)
{
mergeCount++;
left[i] = a[i];
}
for(int i = mid; i<size; i++)
{
mergeCount++;
right[i-mid]=a[i];
}
mergeSort(left);
mergeSort(right);
//merge
merge(left,right,a);
return mergeCount;
}
private static void merge(int [] left, int [] right, int [] a)
{
int leftSize = left.length;
int rightSize = right.length;
int i = 0;//index of the left array
int j = 0; //index of right array
int k = 0; //index of the sorted array [a]
while(i<leftSize && j<rightSize)
{
if(left[i]<=right[j])
{
a[k] = left[i];
i++;
k++;
}
else
{
a[k] = right[j];
j++;
k++;
}
}
while(i<leftSize)
{
a[k] =left[i];
i++;
k++;
}
while(j<rightSize)
{
a[k] =right[j];
j++;
k++;
}
}
public static int quickSort(int[] a, int left, int right)
{
//partition, where pivot is picked
int index = partition(a,left,right);
if(left<index-1)//Still elements on left to be sorted
quickSort(a,left,index-1);
if(index<right) //Still elements on right to be sorted
quickSort(a,index+1,right);
quickCount++;
return quickCount;
}
private static int partition(int[] a, int left, int right)
{
int i = left;
int j = right; //Left and right are indexes
int pivot = a[(left+right/2)]; //Midpoint, pivot
while(i<j)
{
while(a[i]<pivot)
{
i++;
}
while(a[j]>pivot)
{
j--;
}
if(i<=j) //Swap
{
int temp = a[i];
a[i] = a[j];
a[j] = temp;
i++;
j--;
}
}
return i;
}
}
Your infinite loop is in bubbleSort:
public static int bubbleSort(int[] a)
{
boolean hasSwapped = true;
while (hasSwapped == true)
{
hasSwapped = false; // Need to set this to false
for (int i = 0; i < a.length - 1; i++)
{
if (a[i] > a[i + 1]) // Needs to swap
{
int temp = a[i];
a[i] = a[i + 1];
a[i + 1] = temp;
hasSwapped = true;
bubbleCount++;
}
}
}
return bubbleCount;
}
The problem is in your bubbleSort() method. The hasSwapped boolean is never set to false, so the while loops infinite times.
There is another problem in your code. In the main method, you will have to assign the array that the populateArray() method returns back to a. And the such assignments as int[] select = a; you do in the main method do not do what you want to do. Instead, just send the array a to your sorting methods.
Like this:
int[] a = new int[1000];
a=populateArray(a);
testSelection = selectionSort(a);
testBubble = bubbleSort(a);
testQuick = quickSort(a,0,0);
testMerge = mergeSort(a);

Algorithm analysis and structure identification

public class Structure <E extends Comparable<? super E>>{
private E[] d;
public Structure() { d = getArray(1); }
public void show() { show(0); }
private void show(int p){
if( p < d.length && d[p] != null) {
show(r(p));
show(l(p));
System.out.print(d[p] + " ");
}
}
public void add(E obj) {
int p = getPos(obj);
if(p >= d.length)
resize();
d[p] = obj;
}
public boolean present(E obj){
int p = getPos(obj);
return p < d.length && d[p] != null;
}
private int getPos(E obj){
int p = 0;
while(p < d.length && d[p] != null){
int dir = <*1>;
if(dir < 0)
p = l(p);
else if(dir >0)
p = r(p);
else
return p;
}
return p;
}
private E[] getArray(int size) {
return (E[]) new Comparable[size];
}
private void resize(){
E[] temp = getArray(d.length*2 + 1);
for( int i = 0; i < d.length; i++)
temp[i] = d[i];
d = temp;
}
private int l(int i) { return 2 * i + 1;}
private int r(int i) { return 2 * i + 2;}
}
Take that data structure. What is it? I think it's a binary search tree, but I'm pretty sure it's that or a max heap. I'm largely leaning BST, though.
public void fillCol (int n, Collection<Integer> col){
for(int i = 0; i < n; i++)
col.add (i);
}
What is the big O for that method if col is a linked list? I think it's O (N).
And is col a tree set? I think it's O (N log N).
public void sort (List<Double> data){
int lim = data.size();
for(int i = 0; i < lim; i++){
int m = i;
for(int j = i + 1; j < lim; j++)
if(data.get(j) < data.get(m) )
m = j;
data.set( i, data.set(m, data.get(i)));
}
}
and big o for each type of list. I think it's O (N²) for ArrayList and O (N³) for Linked list.
A class that represents a graph uses an adjacency matrix to represent the connections between verticies. What are the space requirements for a graph that contains N nodes with an average of M connections per node?
I think it's O (N²)
Please help! Confirm if I'm right, or correct me if I'm wrong.
It looks like a (not-necessarily-balanced) binary tree, implemented in a manner similar to how a binary heap is often done - in an array where the children of i are 2i and 2i+1.
Someone should've documented what they were doing better.
I agree with your assessment of fillCol.
That sort callable seems like an unrelated question, and yes it does look O(n^2) with a normal data structure.

Categories