In Prim's algorithm, it is recommended to maintain the invariant in the following way :
When a vertice v is added to the MST:
For each edge (v,w) in the unexplored tree:
1. Delete w from the min heap.
2. Recompute the key[w] (i.e. it's value from the unexplored tree
to the explored one).
3. Add the value back to the heap.
So, basically this involves deletion from the heap (and heapify which takes O(logn)) and then reinserting (again O(logn))
Instead, if I use the following approach:
For each edge (v,w) in the unexplored tree:
1. Get the position of the node in the heap(array) using HashMap -> O(1)
2. Update the value in place.
3. Bubble up or bubble down accordingly. -> O(logn)
Which gives better constants than the previous one.
The controversial part is the 3rd part where Im supposed to bubble up or down.
My implementation is as follows :
public int heapifyAt(int index){
// Bubble up
if(heap[index].edgeCost < heap[(int)Math.floor(index/2)].edgeCost){
while(heap[index].edgeCost < heap[(int)Math.floor(index/2)].edgeCost){
swap(index, (int)Math.floor(index/2));
index = (int)Math.floor(index/2);
}
}else{
// Bubble down
while(index*2 + 2 < size && (heap[index].edgeCost > heap[index*2 + 1].edgeCost|| heap[index].edgeCost > heap[index*2 + 2].edgeCost)){
if(heap[index*2 + 1].edgeCost < heap[index*2 + 2].edgeCost){
//swap with left child
swap(index, index*2 + 1);
index = index*2 + 1;
}else{
//swap with right child
swap(index, index*2 + 2);
index = index*2 + 2;
}
}
}
return index;
}
And I'am plucking from the heap this way :
public AdjNode pluck(){
AdjNode min = heap[0];
int minNodeNumber = heap[0].nodeNumber;
AdjNode toRet = new AdjNode(min.nodeNumber, min.edgeCost);
heap[0].edgeCost = INF; // set this to infinity, so it'll be at the bottom
// of the heap.
heapifyat(0);
visited.add(minNodeNumber);
updatevertices(minNodeNumber); // Update the adjacent vertices
return toRet;
}
And updating the plucked vertices this way :
public void updatevertices(int pluckedNode){
for(AdjNode adjacentNode : g.list[pluckedNode]){
if(!visited.contains(adjacentNode.nodeNumber)){ // Skip the nodes that are already visited
int positionInHeap = map.get(adjacentNode.nodeNumber); // Retrive the position from HashMap
if(adjacentNode.edgeCost < heap[positionInHeap].edgeCost){
heap[positionInHeap].edgeCost = adjacentNode.edgeCost; // Update if the cost is better
heapifyAt(positionInHeap); // Now this will go bottom or up, depending on the value
}
}
}
}
But when I execute it on large graph, the code fails, There are small values in the bottom of heap and large values at the top. But the heapifyAt() API seems to work fine. So I am unable to figure out is my approach wrong or my code?
Moreover, if I replace the heapifyAt() API by siftDown(), i.e. construct the heap, it works fine, but it doesnt make sense calling siftDown() that takes O(n) time for every updates which can be processed in logarithmic time.
In short : Is it possible to update the values in Heap both way, or the algorithm is wrong, since that's why it is recommended to first remove the element from Heap and reinsert it.
EDIT : Complete code:
public class Graph1{
public static final int INF = 9999999;
public static final int NEGINF = -9999999;
static class AdjNode{
int nodeNumber;
int edgeCost;
AdjNode next;
AdjNode(int nodeNumber, int edgeCost){
this.nodeNumber = nodeNumber;
this.edgeCost = edgeCost;
}
}
static class AdjList implements Iterable<AdjNode>{
AdjNode head;
AdjList(){
}
public void add(int to, int cost){
if(head==null){
head = new AdjNode(to, cost);
}else{
AdjNode temp = head;
while(temp.next!=null){
temp = temp.next;
}
temp.next = new AdjNode(to, cost);
}
}
public Iterator<AdjNode> iterator(){
return new Iterator<AdjNode>(){
AdjNode temp = head;
public boolean hasNext(){
if(head==null){
return false;
}
return temp != null;
}
public AdjNode next(){
AdjNode ttemp = temp;
temp = temp.next;
return ttemp;
}
public void remove(){
throw new UnsupportedOperationException();
}
};
}
public void printList(){
AdjNode temp = head;
if(head==null){
System.out.println("List Empty");
return;
}
while(temp.next!=null){
System.out.print(temp.nodeNumber + "|" + temp.edgeCost + "-> ");
temp = temp.next;
}
System.out.println(temp.nodeNumber + "|" + temp.edgeCost);
}
}
static class Heap{
int size;
AdjNode[] heap;
Graph g;
int pluckSize;
Set<Integer> visited = new HashSet<Integer>();
HashMap<Integer, Integer> map = new HashMap<>();
Heap(){
}
Heap(Graph g){
this.g = g;
this.size = g.numberOfVertices;
this.pluckSize = size - 1;
heap = new AdjNode[size];
copyElements();
constructHeap();
}
public void copyElements(){
AdjList first = g.list[0];
int k = 0;
heap[k++] = new AdjNode(0, NEGINF); //First entry
for(AdjNode nodes : first){
heap[nodes.nodeNumber] = nodes;
}
for(int i=0; i<size; i++){
if(heap[i]==null){
heap[i] = new AdjNode(i, INF);
}
}
}
public void printHashMap(){
System.out.println("Priniting HashMap");
for(int i=0; i<size; i++){
System.out.println(i + " Pos in heap :" + map.get(i));
}
line();
}
public void line(){
System.out.println("*******************************************");
}
public void printHeap(){
System.out.println("Printing Heap");
for(int i=0; i<size; i++){
System.out.println(heap[i].nodeNumber + " | " + heap[i].edgeCost);
}
line();
}
public void initializeMap(){
for(int i=0; i<size; i++){
map.put(heap[i].nodeNumber, i);
}
}
public void swap(int one, int two){
AdjNode first = heap[one];
AdjNode second = heap[two];
map.put(first.nodeNumber, two);
map.put(second.nodeNumber, one);
AdjNode temp = heap[one];
heap[one] = heap[two];
heap[two] = temp;
}
public void constructHeap(){
for(int i=size-1; i>=0; i--){
int temp = i;
while(heap[temp].edgeCost < heap[(int)Math.floor(temp/2)].edgeCost){
swap(temp, (int)Math.floor(temp/2));
temp = (int)Math.floor(temp/2);
}
}
initializeMap();
}
public void updatevertices(int pluckedNode){
for(AdjNode adjacentNode : g.list[pluckedNode]){
if(!visited.contains(adjacentNode.nodeNumber)){
int positionInHeap = map.get(adjacentNode.nodeNumber);
if(adjacentNode.edgeCost < heap[positionInHeap].edgeCost){
// //System.out.println(adjacentNode.nodeNumber + " not visited, Updating vertice " + heap[positionInHeap].nodeNumber + " from " + heap[positionInHeap].edgeCost + " to " + adjacentNode.edgeCost);
// heap[positionInHeap].edgeCost = INF;
// //heap[positionInHeap].edgeCost = adjacentNode.edgeCost;
// int heapifiedIndex = heapifyAt(positionInHeap); // This code follows my logic
// heap[heapifiedIndex].edgeCost = adjacentNode.edgeCost; // (which doesnt work)
// //heapifyAt(size - 1);
heap[positionInHeap].edgeCost = adjacentNode.edgeCost;
//heapifyAt(positionInHeap);
constructHeap(); // When replaced by SiftDown,
} // works as charm
}
}
}
public void printSet(){
Iterator<Integer> it = visited.iterator();
System.out.print("Printing set : [");
while(it.hasNext()){
System.out.print((int)it.next() + ", ");
}
System.out.println("]");
}
public AdjNode pluck(){
AdjNode min = heap[0];
int minNodeNumber = heap[0].nodeNumber;
AdjNode toRet = new AdjNode(min.nodeNumber, min.edgeCost);
heap[0].edgeCost = INF;
constructHeap();
visited.add(minNodeNumber);
updatevertices(minNodeNumber);
return toRet;
}
public int heapifyAt(int index){
if(heap[index].edgeCost < heap[(int)Math.floor(index/2)].edgeCost){
while(heap[index].edgeCost < heap[(int)Math.floor(index/2)].edgeCost){
swap(index, (int)Math.floor(index/2));
index = (int)Math.floor(index/2);
}
}else{
if(index*2 + 2 < size){
while(index*2 + 2 < size && (heap[index].edgeCost > heap[index*2 + 1].edgeCost|| heap[index].edgeCost > heap[index*2 + 2].edgeCost)){
if(heap[index*2 + 1].edgeCost < heap[index*2 + 2].edgeCost){
//swap with left child
swap(index, index*2 + 1);
index = index*2 + 1;
}else{
//swap with right child
swap(index, index*2 + 2);
index = index*2 + 2;
}
}
}
}
return index;
}
}
static class Graph{
int numberOfVertices;
AdjList[] list;
Graph(int numberOfVertices){
list = new AdjList[numberOfVertices];
for(int i=0; i<numberOfVertices; i++){
list[i] = new AdjList();
}
this.numberOfVertices = numberOfVertices;
}
public void addEdge(int from, int to, int cost){
this.list[from].add(to, cost);
this.list[to].add(from, cost);
}
public void printGraph(){
System.out.println("Printing Graph");
for(int i=0; i<numberOfVertices; i++){
System.out.print(i + " = ");
list[i].printList();
}
}
}
public static void prims(Graph graph, Heap heap){
int totalMin = INF;
int tempSize = graph.numberOfVertices;
while(tempSize>0){
AdjNode min = heap.pluck();
totalMin += min.edgeCost;
System.out.println("Added cost : " + min.edgeCost);
tempSize--;
}
System.out.println("Total min : " + totalMin);
}
public static void main(String[] args) throws Throwable {
Scanner in = new Scanner(new File("/home/mayur/Downloads/PrimsInput.txt"));
Graph graph = new Graph(in.nextInt());
in.nextInt();
while(in.hasNext()){
graph.addEdge(in.nextInt() - 1, in.nextInt() - 1, in.nextInt());
}
Heap heap = new Heap(graph);
prims(graph, heap);
}
}
With a proper implementation of heap, you should be able to bubble up and down. Heap preserves a group of elements using an order that applies to both directions and bubbling up and down are essentially the same, apart from the direction in which you move.
As to your implementation, I believe you are correct but one, seemingly minor issue: indexing.
If you look around for array implementations of heap, you will notice that in most cases the root is located at index 1, instead of 0. The reason for that being, in a 1-indexed array you preserve the following relation between parent p and children c1 and c2.
heap[i] = p
heap[2 * i] = c1
heap[2 * i + 1] = c2
It is trivial to draw an array on a piece of paper and see that this relation holds, if you have the root at heap[1]. The children of root, at index 1, are located at indices 2 and 3. Children of the node at index 2 are at indices 4 & 5, while children of the node at index 3 are at indices 6 & 7, and so on.
This relation helps you get to the children or the parent of any node at i, without having to keep track of where they are. (i.e. parent is at floor(i/2) and children are at 2i and 2i+1)
What you seem to have tried is a 0-indexed implementation of heap. Consequently you had to use a slightly different relation given below for parent p and children c1 and c2.
heap[i] = p
heap[2 * i + 1] = c1
heap[2 * i + 2] = c2
This seems to be ok when accessing the children. For example, the children of root, at index 0, are located at indices 1 and 2. Children of the node at index 1 are at indices 3 & 4, while children of the node at index 2 are at indices 5 & 6, and so on. However there is a pickle when accessing the parent of a node. If you consider node 3 and take floor(3/2), you do get index 1, which is the parent of 1. However, if you take the node at index 4, floor(4/2) gives you index 2, which is not the parent of the node at index 4.
Obviously, this adaptation of the index relationship between a parent and its children does not work for both children. Unlike the 1-indexed heap implementation, you can not treat both children the same while accessing their parents. Therefore, the problem lies specifically in your bubbling up part, without necessarily being related to bubbling up operation. As a matter of fact, though I haven't tested your code, the bubbling up portion of heapifyAt function seems to be correct.(i.e. except the indexing, of course)
Now, you may keep using a 0-indexed heap and adapt your code so that whenever you are looking for a node's parent, you implicitly check whether it is the right (i.e. not as in correct but as in the opposite of left) child of that parent and use floor((i-1)/2) if it is. Checking whether a node is the right child is trivial: just look if it is even or not. (i.e. as you index right children with 2i + 2, they will always be even)
However I recommend you take a different approach and instead use a 1-indexed array implementation of heap. The elegance of the array implementation of heap is that you can treat each node the same and you don't have to do anything different based on its index or location, with the root of the heap perhaps being the only possible exception to this.
Related
My end goal is to do a findKthElement function and the only way I can think of is to perform iterative inorder traversal so that I can keep a counter, which obviously doesn't work if its recursive. I have tried my best at an implementation similar to a BST but its not working, just printing the same thing infinately. Here is my attempt:
public void findKth() {
Stack<BTreeNode> s = new Stack<>();
BTreeNode current = this.root;
while(current != null || !s.isEmpty()) {
int i;
for(i = 0; i < current.numNodes; i++) {
if(!current.isLeaf) {
s.push(current);
current = current.children[i];
}
}
current = s.pop();
for(int j = 0; j < current.numNodes; j++) {
System.out.println(current.keys[j].getName());
}
}
}
keep a counter, which obviously doesn't work if its recursive
There is no problem keeping a counter in a recursive solution. You just need to make sure it's a mutable reference. For example:
public class Counter {
private int count;
public boolean complete() { return count == 0; }
public void decrement() { count--; }
}
Optional<Node> findKthChild(Node node, Counter counter) {
if (counter.isLeaf()) {
if (counter.complete())
return Optional.of(node);
counter.decrement();
} else {
for (Node child: getChildren()) {
Optional<Node> kthChild = findKthChild(child, counter);
if (kthChild.isPresent())
return kthChild;
}
}
return Optional.empty();
}
If you're familiar with streams the internal for loop could be:
return getChildren().stream()
.map(ch -> findKthChild(ch, counter))
.filter(Optional::isPresent)
.findFirst().orElse(Optional.empty());
This reeks of home work. One should try to solve it by tracing the needed steps manually, with pen and paper.
I am not claiming that the code below is correct, or good.
It is to indicate that an in-order traversal, depth first, needs to come back a some nodes ith sub-branch to continue with the next child.
For that I use the new record class as stack element, a class consisting of just BTreeNode node and int index.
public String findKth(int k) {
record NodePos(BTreeNode node, int index) {};
Stack<NodePos> stack = new Stack<>();
stack.push(new NodePos(this.root, -1);
while (!stack.isEmpty()) {
NodePos pos = stack.pop();
pos = new NodePos(pos.node, pos.index + 1);
if (pos.index >= pos.node.numNodes) { // Past end of child nodes.
continue;
}
// Sub-branch:
if (!pos.node.isLeaf) {
stack.push(new NodePos(pos.node.children[pos.index], -1);
continue;
}
// Key:
if (pos.index + 1 >= pos.node.numNodes) { // Past end of child keys.
continue;
}
System.console().printf("%d. %s%n", k, pos.node.keys[pos.index]);
if (k <= 0) {
return pos.node.keys[pos.index];
}
--k;
stack.push(pos);
}
}
There are numNodes sub-branches (node.children)and numNodes - 1 keys in a node (node.keys).
When you are at the i th sub-branch, you may first continue with the subtree, and when not sufficient (decreasing k still greater 0), then continue with the i-1 th key.
As you see, when not manually executing the code, it is hard to read it. For that it invaluable advice to work out these things yourself.
A recursive solution is easier by the way.
Okay, a working solution
My answer above was intended to think about, certainly not correct,
as the OP did not show having seriously thought about the algorithm,
given the OPs code. But there is effort evidently.
Hence a readable recursive solution. Still in a form which cannot
be given back as ones own home work.
static class BTreeNode {
int numNodes;
boolean isLeaf;
BTreeNode[] children;
int[] keys;
BTreeNode(int... keys) {
numNodes = keys.length + 1;
this.keys = keys.clone();
isLeaf = true;
}
public void addChildren(BTreeNode... children) {
assert children.length == numNodes;
this.children = children.clone();
isLeaf = false;
}
}
public static OptionalInt findKth(BTreeNode node, AtomicInteger k) {
if (node == null || k.get() < 0) {
return OptionalInt.empty();
}
for (int i = 0; i < node.numNodes; ++i) {
if (!node.isLeaf) {
OptionalInt result = findKth(node.children[i], k);
if (result.isPresent()) {
return result;
}
}
if (i + 1 < node.numNodes) {
int j = k.getAndDecrement();
System.out.printf("%d. %s%n", j, node.keys[i]);
if (j <= 0) {
return OptionalInt.of(node.keys[i]);
}
}
}
return OptionalInt.empty();
}
public static void main(String[] args) {
//
// (4 8 12)
// (1 2 3) (5 6 7) (9 10 11) (13 14 15)
BTreeNode n1to3 = new BTreeNode(1, 2, 3);
BTreeNode n5to7 = new BTreeNode(5, 6, 7);
BTreeNode n9to11 = new BTreeNode(9, 10, 11);
BTreeNode n13to15 = new BTreeNode(13, 14, 15);
BTreeNode root = new BTreeNode(4, 8, 12);
root.addChildren(n1to3, n5to7, n9to11, n13to15);
OptionalInt key5 = findKth(root, new AtomicInteger(5));
System.out.println("The result is " + key5.orElse(-1));
}
One walks in-order through the B-tree decrementing the asked k till it reaches 0. The in-order walk with numNodes subtree branches and numNodes - 1 keys requires a for+if.
The AtomicInteger is used to have a counter, a result from findKth otherwise one would need an input parameter k, and a new value for k on return. That can be done.
Optimisation: One could skip visiting a subtree, if one knew the number of elements in an entire subtree. For leaf nodes that would be numNodes.
I am trying to create a min heap but I am running into the issue where the numbers that are being displayed in my min heap are all in random order and there are extra 0's where there should be different values. This is the code for my class that does most of the work:
public class Heap211 {
static Random rand = new Random();
static public int[] Heap;
static public int size;
Heap211(){
Heap = new int[30];
size = 0;
}
static public int parent(int index){//location of parent
return index / 2;//array[k / 2]
}
static public int leftChild(int index){//location of left child
return index * 2;//array[k * 2]
}
static public int rightChild(int index){//location of right child
return index * 2 + 1;//array[k * 2 + 1]
}
static public boolean hasParent(int index){
return index > 1;
}
static public boolean hasLeftChild(int index){
return leftChild(index) * 2 <= size;
}
static public boolean hasRightChild(int index){
return rightChild(index * 2) + 1 <= size;
}
static public void swap(int[] a, int index1, int index2){//swaps nodes
int temp = a[index1];
a[index1] = a[index2];
a[index2] = temp;
}
static public int peek(){//peeks at the top of the stack (min value)
return Heap[1];
}
public static boolean isEmpty(){
return size == 0;
}
static int randInt(int min, int max){//generates random int between two numbers
return ((int) (Math.random()*(max - min))) + min;
}
public String toString(){
String result = "[";
if(!isEmpty()){
result += Heap[1];
for(int i = 2; i <= size; i++){
result += ", " + Heap[i];
}
}
return result + "]";
}
public void add(int value){//adds the give value to this priority queue in order
if(size + 1 >= Heap.length){
Heap = Arrays.copyOf(Heap, Heap.length * 2);
}
size++;
Heap[size + 1] = value;//add as rightmost leaf
//"bubble up" as necessary to fix ordering
int index = size + 1;
boolean found = false;
while(!found && hasParent(index) && hasLeftChild(index)){
int parent = parent(index);
if(Heap[index] < Heap[parent]){
swap(Heap, index, parent(index));
index = parent(index);
}else{//after done bubbling up
found = true;
}
}
}
public int remove(){
//move rightmost leaf to become new root
int result = peek();//last leaf -> root
Heap[1] = Heap[size];
size--;
//"bubble down" as necessary to fix ordering
int index = 1;
boolean found = false;
while(!found && hasLeftChild(index)){
int left = leftChild(index);
int right = rightChild(index);
int child = left;
if(hasRightChild(index) && Heap[right] < Heap[left]){
child = right;
}
if(Heap[index] > Heap[child]){
swap(Heap, index, child);
index = child;
}else{
found = true;//found proper location, stop the loop
}
}
return result;
}
This is the code for my main class:
public static void main(String[] args){
Heap211 pq = new Heap211();
for(int node = 1;node <= 30; node++){//loop runs 30 times for 30 nodes
int smValue = randInt(0,2);//generates random number between 1 and 0
if(smValue == 0){//if random number is 0 then it will add random number to heap
int value = randInt(0,100);//generates random number between 0 and 100
System.out.println(node + " Add " + value + ": ");
pq.add(value);//adds random number
System.out.println(pq);//print heap
}else if(smValue == 1 && pq.isEmpty()){
int value = pq.remove();
System.out.println(node + " Remove " + value + ": ");
System.out.println(pq);
}
}
I have a GUI that displays all the numbers but I am getting the wrong output. Any helpful pointers would be greatly appreciated! Thanks.
I found a few problems in your code.
Your hasLeftChild function is wrong. You have return leftChild(index*2) <= size;. But you really should be checking for leftChild(index) <= size. You have a similar error in your hasRightChild function.
Not sure why you pass an array parameter to swap. The only array in which you swap stuff is the Heap array, which is a member of the class.
You have an error in your add method. You increment the size, and then add an item. That is:
size++;
Heap[size + 1] = value;
So imagine what happens when you add the first item. size is equal to 0, and you increment it to 1. Then you add the value at index size+1. So your array contains [0, 0, value]. That's probably the source of your extra 0's. I think what you want is:
Heap[size] = value;
size++;
You'll have to modify the rest of your code to take that into account.
Your "bubble up" loop is kind of wonky. You have:
while (!found && hasParent(index) && hasLeftChild(index))
That's never going to bubble anything up, because when you add something to the last element of the heap, that node doesn't have a left child. You also don't need the found flag. You can write:
while (hasParent(index) && Heap[index] < Heap[parent]]) {
swap(Heap, index, parent(index));
index = parent(index);
}
I can't guarantee that those are the only errors in your code, but they're the ones I found in a quick review of your code.
On a general note, why in the world are you creating a 1-based binary heap in a language that has 0-based arrays? There's no need to do that, and it's confusing as heck. For why I think it's a bad idea, see https://stackoverflow.com/a/49806133/56778 and http://blog.mischel.com/2016/09/19/but-thats-the-way-weve-always-done-it/.
Finally, you should learn to use your debugger, as suggested in comments. Take the time to do it now. It will save you hours of frustration.
I have a program that reads in a text file and creates a number of nodes elements that can be used to build into a MIN heap.
What I'm struggling with is, after the Min heap has been correctly built, I'm supposed to sort the elements by using an 'extract' method to remove the smallest element at the root and adding it to a separate ArrayList intended to contain the elements in sorted order.
Of course we are supposed to extract one element at a time and add it to our new arraylist and then, remove that element from the heap of remaining nodes, so that the heap keeps decreasing by one element and the sorted arraylist keeps increasing by one element until there are no remaining elements in the heap.
I believe the problem is that after extracting the root element of the min heap, the root element itself isn't erased, it seems to remain in the heap even though my extract method is supposed to overwrite the removed root element by replacing it with the last item in the heap and then decrementing the heap size and re-applying the 'heapify' method to restore the heap property.
My code is fairly simple, the main method is long but the significant part is as follows:
g = new Graph();
readGraphInfo( g );
DelivB dB = new DelivB(inputFile, g);
int numElements = g.getNodeList().size();
ArrayList<Node> ordered_nodeList = new ArrayList<Node>(15);
ArrayList<Node> sorted_nodeList = new ArrayList<Node>(15);
h = new Heap(ordered_nodeList, g);
for (int i = 0; i < numElements; i++)
{
ordered_nodeList.add(i, g.getNodeList().get(i));
h.Build_min_Heap(ordered_nodeList);
System.out.println("Heap: \n");
System.out.println("\n**********************" + "\nProg 340 line 147" +h.heapClass_toString(ordered_nodeList));
//System.out.println("the " + i + "th item added at index " + i + " is: " + ordered_nodeList.get(i).getAbbrev());
}
for (int j = 0; j < numElements; j++)
{
sorted_nodeList.add(j, h.heap_Extract(ordered_nodeList));
System.out.println("the "+j+"th item added to SORTED node list is: "+sorted_nodeList.get(j).getAbbrev()+ " "+ sorted_nodeList.get(j).getVal());
//h.heap_Sort(ordered_nodeList);
System.out.println("\nthe 0th remaining element in ordered node list is: " + ordered_nodeList.get(0).getVal());
h.Build_min_Heap(ordered_nodeList);
}
for (Node n : sorted_nodeList)
{
System.out.println("sorted node list after extract method*****************\n");
System.out.println(n.toString());
}
The output I keep getting is as follows:
the 0th remaining element in ordered node list is: 55
the 1th item added to SORTED node list is: F 55
the 0th remaining element in ordered node list is: 55
the 2th item added to SORTED node list is: F 55
the 0th remaining element in ordered node list is: 55
the 3th item added to SORTED node list is: F 55
the 0th remaining element in ordered node list is: 55
the 4th item added to SORTED node list is: F 55
the 0th remaining element in ordered node list is: 55
the 5th item added to SORTED node list is: F 55
the 0th remaining element in ordered node list is: 55
sorted node list after extract method*****************
F
sorted node list after extract method*****************
F
sorted node list after extract method*****************
F
sorted node list after extract method*****************
F
sorted node list after extract method*****************
F
sorted node list after extract method*****************
F
My Heap class is as follows:
import java.util.*;
public class Heap
{
int heapSize;
ArrayList unordered_nodeList;
ArrayList ordered_nodeList;
Graph gr;
nodes
public Heap(ArrayList<Node> A, Graph g)
{
unordered_nodeList = g.getNodeList();
heapSize = unordered_nodeList.size();
ordered_nodeList = A;
gr = g;
}
public ArrayList getUnordered_nodeList() {
return unordered_nodeList;
}
public void setUnordered_nodeList(ArrayList unordered_nodeList) {
this.unordered_nodeList = unordered_nodeList;
}
public ArrayList getOrdered_nodeList() {
return ordered_nodeList;
}
public void setOrdered_nodeList(ArrayList ordered_nodeList) {
this.ordered_nodeList = ordered_nodeList;
}
public int getHeapSize() {
return heapSize;
}
public void setHeapSize(int heapSize) {
this.heapSize = heapSize;
}
//heap methods
public int Parent(ArrayList<Node> A, int i)
{
//if (i == 1)
//return (Integer)null;
if (i%2 != 0)
return i/2;
else
return (i-1)/2;
}
public int Left(ArrayList<Node> A, int i)
{
if (2*i < A.size()-1)
return (2*i)+1;
else
return i;
//return (Integer)null;
}
public int Right(ArrayList<Node> A, int i)
{
if ((2*i)+1 < A.size()-1)
return 2*i+2;
else
return i;
//return (Integer)null;
}
public void Heapify(ArrayList<Node> A, int i)
{
Node smallest;
Node temp;
int index;
int l = Left(A,i);
int r = Right(A,i);
if (l <= heapSize-1 && Integer.parseInt(A.get(l).getVal()) < Integer.parseInt(A.get(i).getVal()))
{
//left child is smaller
smallest = A.get(l);
index = l;
}
else
{
//parent node is smaller
smallest = A.get(i);
index = i;
}
if (r <= heapSize-2 && Integer.parseInt(A.get(r).getVal()) < Integer.parseInt(smallest.getVal()))
{
//right child is smaller
smallest = A.get(r);
index = r;
}
if (index != i)
{
//if the smallest element is not the parent node
//swap the smallest child with the parent
temp = A.get(i);
A.set(i, A.get(index));
A.set(index, temp);
//recursively call heapify method to check next parent/child relationship
Heapify(A, index);
//System.out.println(this.heapClass_toString(ordered_nodeList));
}
//System.out.println("\n**********************" + "\nHeapify line 123" + this.heapClass_toString(ordered_nodeList));
}
//method to construct min heap from unordered arraylist of nodes
public void Build_min_Heap(ArrayList<Node> A)
{
int i;
int heapSize = A.size();
for (i = (heapSize/2); i>=0; i--)
{
//System.out.println(gr.toString2() +"\n");
//System.out.println("build heap ********** line 138" +this.heapClass_toString(ordered_nodeList));
Heapify(A, i);
//System.out.print(gr.toString2()+"\n");
}
}
//method to sort in descending order, a min heap
public void heap_Sort(ArrayList<Node> A)
{
Node temp;
//Build_min_Heap(A);
while (A.size() > 0)
{
///System.out.println("\n******************************\n heap_sort line 180" +this.heapClass_toString(ordered_nodeList));
//for (int i = 0; i <= A.size()-1; i++)
for(int i = A.size()-1; i >= 1; i--)
{
//exchange a[0] with a[i]
temp = A.get(0);
A.set(0, A.get(i));
A.set(i, temp);
//System.out.println(this.heapClass_toString(ordered_nodeList));
//decrement heapSize
heapSize--;
//recursive heapify call
Heapify(A, 0);
System.out.println("\n******************************\n heap_sort line 203" +this.heapClass_toString(ordered_nodeList));
}
System.out.println("\n******************************\n heap_sort line 206" +this.heapClass_toString(ordered_nodeList));
Heapify(A, A.size()-1);
}
}
public Node heap_Extract(ArrayList<Node> A)
{
//Node min = null;
//if (heapSize>0)
//while (A.get(0) != null && heapSize > 0)
Node min = A.get(0);
//min = A.get(0);
while (heapSize>0)
{
min = A.get(0);
A.set(0, A.get(heapSize-1));
//decrement heapSize
heapSize--;
Heapify(A, 0);
}
return min;
}
//return min;
public String heapClass_toString(ArrayList A)
{
String s = "Graph g.\n";
if (A.size() > 0 )
{
for (int k = 0; k < A.size(); k++ )
{
//output string to print each node's mnemonic
String t = this.getOrdered_nodeList().get(k).toString();
s = s.concat(t);
}
}
return s;
}
}
One issue is the following loop in your heap_Extract() method:
while (heapSize>0)
{
min = A.get(0);
A.set(0, A.get(heapSize-1));
//decrement heapSize
heapSize--;
Heapify(A, 0);
}
This loop will run over and over again until your heap has nothing in it, and then the function will return the last node min was set to (which should be the largest element in the original heap, if Heapify is implemented correctly). Subsequent calls will see that heapSize == 0, skip the loop entirely, and immediately and return min, which will be set to A.get(0), which will still be the largest element in the original Heap. You should ensure that the code in the body of this loop only runs at most one time (i.e. it shouldn't be in a loop, but perhaps should be guarded by some other conditional branch statement) for each call of heap_Extract().
I want to reduce the complexity of this program and find count of elements greater than current/picked element in first loop (array[])and store the count in solved array(solved[]) and loop through the end of the array[]. I have approached the problem using a general array based approach which turned out to have greater time complexity when 2nd loop is huge.
But If someone can suggest a better collection here in java that can reduce the complexity of this code that would also be highly appreciated.
for (int i = 0; i < input; i++) {
if (i < input - 1) {
count=0;
for (int j = i+1; j < input; j++) {
System.out.print((array[i])+" ");
System.out.print("> ");
System.out.print((array[j]) +""+(array[i] > array[j])+" ");
if (array[i] > array[j]) {
count++;
}
}
solved[i] = count;
}
}
for (int i = 0; i < input; i++) {
System.out.print(solved[i] + " ");
}
What I want to achieve in simpler terms
Input
Say I have 4 elements in my
array[] -->86,77,15,93
output
solved[]-->2 1 0 0
2 because after 86 there are only two elements 77,15 lesser than 86
1 because after 77 there is only 15 lesser than 77
rest 15 <93 hence 0,0
So making the code simpler and making the code faster aren't necessarily the same thing. If you want the code to be simple and readable, you could try a sort. That is, you could try something like
int[] solved = new int[array.length];
for (int i = 0; i < array.length; i++){
int[] afterward = Arrays.copyOfRange(array, i, array.length);
Arrays.sort(afterward);
solved[i] = Arrays.binarySearch(afterward, array[i]);
}
What this does it it takes a copy of the all the elements after the current index (and also including it), and then sorts that copy. Any element less than the desired element will be beforehand, and any element greater will be afterward. By finding the index of the element, you're finding the number of indices before it.
A disclaimer: There's no guarantee that this will work if duplicates are present. You have to manually check to see if there are any duplicate values, or otherwise somehow be sure you won't have any.
Edit: This algorithm runs in O(n2 log n) time, where n is the size of the original list. The sort takes O(n log n), and you do it n times. The binary search is much faster than the sort (O(log n)) so it gets absorbed into the O(n log n) from the sort. It's not perfectly optimized, but the code itself is very simple, which was the goal here.
With Java 8 streams you could reimplement it like this:
int[] array = new int[] { 86,77,15,93 };
int[] solved =
IntStream.range(0, array.length)
.mapToLong((i) -> Arrays.stream(array, i + 1, array.length)
.filter((x) -> x < array[i])
.count())
.mapToInt((l) -> (int) l)
.toArray();
There is actually a O(n*logn) solution, but you should use a self balancing binary search tree such as red-black tree.
Main idea of the algorithm:
You will iterate through your array from right to left and insert in the tree triples (value, sizeOfSubtree, countOfSmaller). Variable sizeOfSubtree will indicate the size of the subtree rooted at that element, while countOfSmaller counts the number of elements that are smaller than this element and appear at the right side of it in the original array.
Why binary search tree? An important property of BST is that all nodes in the left subtree are smaller than the current node, and all in the right subtree are greater.
Why self-balancing tree? Because this will guarantee you O(logn) time complexity while inserting a new element, so for n elements in array that will give O(n*logn) in total.
When you insert a new element you will also calculate the value of countOfSmaller by counting elements that are currently in the tree and are smaller than this element - exactly what are we looking for. Upon inserting in the tree compare the new element with the existing nodes, starting with the root. Important: if the value of the new element is greater than the value of the root, it means that is also greater than all the nodes in the left subtree of root. Therefore, set countOfSmaller to the sizeOfSubtree of root's left child + 1 (because the new element is also greater than root) and proceed recursively in the right subtree. If it is smaller than root, it goes to the left subtree of root. In both cases increment sizeOfSubtree of root and proceed recursively. While rebalancing the tree, just update the sizeOfSubtree for nodes that are included in left/right rotation and that's it.
Sample code:
public class Test
{
static class Node {
public int value, countOfSmaller, sizeOfSubtree;
public Node left, right;
public Node(int val, int count) {
value = val;
countOfSmaller = count;
sizeOfSubtree = 1; /** You always add a new node as a leaf */
System.out.println("For element " + val + " the number of smaller elements to the right is " + count);
}
}
static Node insert(Node node, int value, int countOfSmaller)
{
if (node == null)
return new Node(value, countOfSmaller);
if (value > node.value)
node.right = insert(node.right, value, countOfSmaller + size(node.left) + 1);
else
node.left = insert(node.left, value, countOfSmaller);
node.sizeOfSubtree = size(node.left) + size(node.right) + 1;
/** Here goes the rebalancing part. In case that you plan to use AVL, you will need an additional variable that will keep the height of the subtree.
In case of red-black tree, you will need an additional variable that will indicate whether the node is red or black */
return node;
}
static int size(Node n)
{
return n == null ? 0 : n.sizeOfSubtree;
}
public static void main(String[] args)
{
int[] array = {13, 8, 4, 7, 1, 11};
Node root = insert(null, array[array.length - 1], 0);
for(int i = array.length - 2; i >= 0; i--)
insert(root, array[i], 0); /** When you introduce rebalancing, this should be root = insert(root, array[i], 0); */
}
}
As Miljen Mikic pointed out, the correct approach is using RB/AVL tree. Here is the code that can read and N testcase do the job as quickly as possible. Accepting Miljen code as the best approach to the given problem statement.
class QuickReader {
static BufferedReader quickreader;
static StringTokenizer quicktoken;
/** call this method to initialize reader for InputStream */
static void init(InputStream input) {
quickreader = new BufferedReader(new InputStreamReader(input));
quicktoken = new StringTokenizer("");
}
static String next() throws IOException {
while (!quicktoken.hasMoreTokens()) {
quicktoken = new StringTokenizer(quickreader.readLine());
}
return quicktoken.nextToken();
}
static int nextInt() throws IOException {
return Integer.parseInt(next());
}
static long nextLong() throws IOException {
return Long.parseLong(next());
}
static double nextDouble() throws IOException {
return Double.parseDouble(next());
}
}
public class ExecuteClass{
static int countInstance = 0;
static int solved[];
static int size;
static class Node {
public int value, countOfSmaller, sizeOfSubtree;
public Node left, right;
public Node(int val, int count, int len, int... arraytoBeused) {
countInstance++;
value = val;
size = len;
countOfSmaller = count;
sizeOfSubtree = 1; /** You always add a new node as a leaf */
solved = arraytoBeused;
solved[size - countInstance] = count;
}
}
static Node insert(Node node, int value, int countOfSmaller, int len, int solved[]) {
if (node == null)
return new Node(value, countOfSmaller, len, solved);
if (value > node.value)
node.right = insert(node.right, value, countOfSmaller + size(node.left) + 1, len, solved);
else
node.left = insert(node.left, value, countOfSmaller, len, solved);
node.sizeOfSubtree = size(node.left) + size(node.right) + 1;
return node;
}
static int size(Node n) {
return n == null ? 0 : n.sizeOfSubtree;
}
public static void main(String[] args) throws IOException {
QuickReader.init(System.in);
int testCase = QuickReader.nextInt();
for (int i = 1; i <= testCase; i++) {
int input = QuickReader.nextInt();
int array[] = new int[input];
int solved[] = new int[input];
for (int j = 0; j < input; j++) {
array[j] = QuickReader.nextInt();
}
Node root = insert(null, array[array.length - 1], 0, array.length, solved);
for (int ii = array.length - 2; ii >= 0; ii--)
insert(root, array[ii], 0, array.length, solved);
for (int jj = 0; jj < solved.length; jj++) {
System.out.print(solved[jj] + " ");
}
System.out.println();
countInstance = 0;
solved = null;
size = 0;
root = null;
}
}
}
I'm trying to write a program that'll find the MST of a given undirected weighted graph with Kruskal's and Prim's algorithms. I've successfully implemented Kruskal's algorithm in the program, but I'm having trouble with Prim's. To be more precise, I can't figure out how to actually build the Prim function so that it'll iterate through all the vertices in the graph. I'm getting some IndexOutOfBoundsException errors during program execution. I'm not sure how much information is needed for others to get the idea of what I have done so far, but hopefully there won't be too much useless information.
This is what I have so far:
I have a Graph, Edge and a Vertex class.
Vertex class mostly just an information storage that contains the name (number) of the vertex.
Edge class can create a new Edge that has gets parameters (Vertex start, Vertex end, int edgeWeight). The class has methods to return the usual info like start vertex, end vertex and the weight.
Graph class reads data from a text file and adds new Edges to an ArrayList. The text file also tells us how many vertecis the graph has, and that gets stored too.
In the Graph class, I have a Prim() -method that's supposed to calculate the MST:
public ArrayList<Edge> Prim(Graph G) {
ArrayList<Edge> edges = G.graph; // Copies the ArrayList with all edges in it.
ArrayList<Edge> MST = new ArrayList<Edge>();
Random rnd = new Random();
Vertex startingVertex = edges.get(rnd.nextInt(G.returnVertexCount())).returnStartingVertex(); // This is just to randomize the starting vertex.
// This is supposed to be the main loop to find the MST, but this is probably horribly wrong..
while (MST.size() < returnVertexCount()) {
Edge e = findClosestNeighbour(startingVertex);
MST.add(e);
visited.add(e.returnStartingVertex());
visited.add(e.returnEndingVertex());
edges.remove(e);
}
return MST;
}
The method findClosesNeighbour() looks like this:
public Edge findClosestNeighbour(Vertex v) {
ArrayList<Edge> neighbours = new ArrayList<Edge>();
ArrayList<Edge> edges = graph;
for (int i = 0; i < edges.size() -1; ++i) {
if (edges.get(i).endPoint() == s.returnVertexID() && !visited(edges.get(i).returnEndingVertex())) {
neighbours.add(edges.get(i));
}
}
return neighbours.get(0); // This is the minimum weight edge in the list.
}
ArrayList<Vertex> visited and ArrayList<Edges> graph get constructed when creating a new graph.
Visited() -method is simply a boolean check to see if ArrayList visited contains the Vertex we're thinking about moving to. I tested the findClosestNeighbour() independantly and it seemed to be working but if someone finds something wrong with it then that feedback is welcome also.
Mainly though as I mentioned my problem is with actually building the main loop in the Prim() -method, and if there's any additional info needed I'm happy to provide it.
Thank you.
Edit: To clarify what my train of thought with the Prim() method is. What I want to do is first randomize the starting point in the graph. After that, I will find the closest neighbor to that starting point. Then we'll add the edge connecting those two points to the MST, and also add the vertices to the visited list for checking later, so that we won't form any loops in the graph.
Here's the error that gets thrown:
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at Graph.findClosestNeighbour(graph.java:203)
at Graph.Prim(graph.java:179)
at MST.main(MST.java:49)
Line 203: return neighbour.get(0); in findClosestNeighbour()
Line 179: Edge e = findClosestNeighbour(startingVertex); in Prim()
Vertex startingVertex = edges.get(rnd.nextInt(G.returnVertexCount())).returnStartingVertex();
This uses the vertex count to index an edge list, mixing up vertices and edges.
// This is supposed to be the main loop to find the MST, but this is probably horribly wrong..
while (MST.size() < returnVertexCount()) {
Edge e = findClosestNeighbour(startingVertex);
MST.add(e);
visited.add(e.returnStartingVertex());
visited.add(e.returnEndingVertex());
edges.remove(e);
}
This shouldn't be passing the same startingVertex to findClosestNeighbour each time.
public Edge findClosestNeighbour(Vertex v) {
ArrayList<Edge> neighbours = new ArrayList<Edge>();
ArrayList<Edge> edges = graph;
for (int i = 0; i < edges.size() -1; ++i) {
if (edges.get(i).endPoint() == s.returnVertexID() && !visited(edges.get(i).returnEndingVertex())) {
neighbours.add(edges.get(i));
}
}
return neighbours.get(0); // This is the minimum weight edge in the list.
}
What is s here? This doesn't look like it's taking the edge weights into account. It's skipping the last edge, and it's only checking the ending vertex, when the edges are non-directional.
// Simple weighted graph representation
// Uses an Adjacency Linked Lists, suitable for sparse graphs /*undirected
9
A
B
C
D
E
F
G
H
I
A B 1
B C 2
C E 7
E G 1
G H 8
F H 3
F D 4
D E 5
I F 9
I A 3
A D 1
This is the graph i used saved as graph.txt
*/
import java.io.*;
import java.util.Scanner;
class Heap
{
private int[] h; // heap array
private int[] hPos; // hPos[h[k]] == k
private int[] dist; // dist[v] = priority of v
private int MAX;
private int N; // heap size
// The heap constructor gets passed from the Graph:
// 1. maximum heap size
// 2. reference to the dist[] array
// 3. reference to the hPos[] array
public Heap(int maxSize, int[] _dist, int[] _hPos)
{
N = 0;
MAX = maxSize;
h = new int[maxSize + 1];
dist = _dist;
hPos = _hPos;
}
public boolean isEmpty()
{
return N == 0;
}
public void siftUp( int k)
{
int v = h[k];
h[0] = 0;
dist[0] = Integer.MIN_VALUE;
//vertex using dist moved up heap
while(dist[v] < dist[h[k/2]]){
h[k] = h[k/2]; //parent vertex is assigned pos of child vertex
hPos[h[k]] = k;//hpos modified for siftup
k = k/2;// index of child assigned last parent to continue siftup
}
h[k] = v;//resting pos of vertex assigned to heap
hPos[v] = k;//index of resting pos of vertex updated in hpos
//display hpos array
/* System.out.println("\nThe following is the hpos array after siftup: \n");
for(int i = 0; i < MAX; i ++){
System.out.println("%d", hPos[i]);
}
System.out.println("\n Following is heap array after siftup: \n");
for (int i = 0; i < MAX; i ++ ){
System.out.println("%d" , h[i]);
}*/
}
//removing the vertex at top of heap
//passed the index of the smallest value in heap
//siftdown resizes and resorts heap
public void siftDown( int k)
{
int v, j;
v = h[k];
while(k <= N/2){
j = 2 * k;
if(j < N && dist[h[j]] > dist[h[j + 1]]) ++j; //if node is > left increment j child
if(dist[v] <= dist[h[j]]) break;//if sizeof parent vertex is less than child stop.
h[k] = h[j];//if parent is greater than child then child assigned parent pos
hPos[h[k]] = k;//update new pos of last child
k = j;//assign vertex new pos
}
h[k] = v;//assign rest place of vertex to heap
hPos[v] = k;//update pos of the vertex in hpos array
}
public void insert( int x)
{
h[++N] = x;//assign new vertex to end of heap
siftUp( N);//pass index at end of heap to siftup
}
public int remove()
{
int v = h[1];
hPos[v] = 0; // v is no longer in heap
h[N+1] = 0; // put null node into empty spot
h[1] = h[N--];//last node of heap moved to top
siftDown(1);//pass index at top to siftdown
return v;//return vertex at top of heap
}
}
class Graph {
class Node {
public int vert;
public int wgt;
public Node next;
}
// V = number of vertices
// E = number of edges
// adj[] is the adjacency lists array
private int V, E;
private Node[] adj;
private Node z;
private int[] mst;
// used for traversing graph
private int[] visited;
private int id;
// default constructor
public Graph(String graphFile) throws IOException
{
int u, v;
int e, wgt;
Node t;
FileReader fr = new FileReader(graphFile);
BufferedReader reader = new BufferedReader(fr);
String splits = " +"; // multiple whitespace as delimiter
String line = reader.readLine();
String[] parts = line.split(splits);
System.out.println("Parts[] = " + parts[0] + " " + parts[1]);
V = Integer.parseInt(parts[0]);
E = Integer.parseInt(parts[1]);
// create sentinel node
z = new Node();
z.next = z;
// create adjacency lists, initialised to sentinel node z
adj = new Node[V+1];
for(v = 1; v <= V; ++v)
adj[v] = z;
// read the edges
System.out.println("Reading edges from text file");
for(e = 1; e <= E; ++e)
{
line = reader.readLine();
parts = line.split(splits);
u = Integer.parseInt(parts[0]);
v = Integer.parseInt(parts[1]);
wgt = Integer.parseInt(parts[2]);
System.out.println("Edge " + toChar(u) + "--(" + wgt + ")--" + toChar(v));
// write code to put edge into adjacency matrix
t = new Node(); t.vert = v; t.wgt = wgt; t.next = adj[u]; adj[u] = t;
t = new Node(); t.vert = u; t.wgt = wgt; t.next = adj[v]; adj[v] = t;
}
}
// convert vertex into char for pretty printing
private char toChar(int u)
{
return (char)(u + 64);
}
// method to display the graph representation
public void display() {
int v;
Node n;
for(v=1; v<=V; ++v){
System.out.print("\nadj[" + toChar(v) + "] ->" );
for(n = adj[v]; n != z; n = n.next)
System.out.print(" |" + toChar(n.vert) + " | " + n.wgt + "| ->");
}
System.out.println("");
}
//use the breath first approach to add verts from the adj list to heap
//uses 3 arrays where array = # of verts in graph
//parent array to keep track of parent verts
// a dist matrix to keep track of dist between it and parent
//hpos array to track pos of vert in the heap
public void MST_Prim(int s)
{
int v, u;
int wgt, wgt_sum = 0;
int[] dist, parent, hPos;
Node t;
//declare 3 arrays
dist = new int[V + 1];
parent = new int[V + 1];
hPos = new int[V +1];
//initialise arrays
for(v = 0; v <= V; ++v){
dist[v] = Integer.MAX_VALUE;
parent[v] = 0;
hPos[v] = 0;
}
dist[s] = 0;
//d.dequeue is pq.remove
Heap pq = new Heap(V, dist, hPos);
pq.insert(s);
while (! pq.isEmpty())
{
// most of alg here
v = pq.remove();
wgt_sum += dist[v];//add the dist/wgt of vert removed to mean spanning tree
//System.out.println("\nAdding to MST edge {0} -- ({1}) -- {2}", toChar(parent[v]), dist[v], toChar[v]);
dist[v] = -dist[v];//mark it as done by making it negative
for(t = adj[v]; t != z; t = t.next){
u = t.vert;
wgt = t.wgt;
if(wgt < dist[u]){ //weight less than current value
dist[u] = wgt;
parent[u] = v;
if(hPos[u] == 0)// not in heap insert
pq.insert(u);
else
pq.siftUp(hPos[u]);//if already in heap siftup the modified heap node
}
}
}
System.out.print("\n\nWeight of MST = " + wgt_sum + "\n");
//display hPos array
/*System.out.println("\nhPos array after siftUp: \n");
for(int i = 0; i < V; i ++){
System.out.println("%d", hPos[i]);
}*/
mst = parent;
}
public void showMST()
{
System.out.print("\n\nMinimum Spanning tree parent array is:\n");
for(int v = 1; v <= V; ++v)
System.out.println(toChar(v) + " -> " + toChar(mst[v]));
System.out.println("");
}
}
public class PrimLists {
public static void main(String[] args) throws IOException
{
int s = 2;
String fname = "graph.txt";
Graph g = new Graph(fname);
g.display();
}
}