Implementing a Graph using a HashMap - java

I'm new to Java, so please keep that in mind before getting trigger happy down-voting. I'm familiar with the popular implementation of a graph of integers using an array.
Graph{
int vertices;
LinkedList<Integer>[] adj;
Graph(int vertices){
this.vertices = vertices;
adj = new LinkedList<>();
for(int i= 0; i <vertices; i++){
adj[i] = new LinkedList();
}
}
However this implementation is best suited to a graph of integers.
In case I want to implmentation graph of Characters, this implemetation doesn't render itself directly usable.
So I tried implementing using a HashMap.
public class Graph {
int vertices;
HashMap<Character, LinkedList<Character>> adj;
Graph(int item){
this.vertices = item;
adj = new HashMap<>();
}
}
Where I'm a little stuck syntactically with Java is adding keys and values to this HashTable. What I'm trying to do is implement this method.
public void add(Character a, Character b){
if (adj.containsKey(a)){
//get a reference to the existing linked list
//add to the existing LinkedList
}else{
//create a new LinkedList and add to it.
}
}
}
I could use some help with the incomplete add method as also how to iterate through the this adj HashMap once the graph is constructed.

Since your question is only about syntax, you can do something like this:
public void add(Character a, Character b){
if (adj.containsKey(a)){
//get a reference to the existing linked list
LinkedList<Character> l = adj.get(a);
//add to the existing LinkedList
//You need to do a null check here to make sure (l != null)
l.add(b)
}else{
//create a new LinkedList and add to it.
LinkedList<Character> l = new LinkedList<Character>();
l.add(b);
adj.put(a, l);
}
}
}

HashMap stores the node number as key and the list of all the adjacent nodes as value. The list has been implemented using LinkedList class. Just change the class of Key and value according to your requirement.
class Graph{
HashMap<Integer,LinkedList<Integer>> map = new HashMap<>();
//add an edge from source to destination
void addEdge(int src, int dest){
if(!map.containsKey(src)){
LinkedList<Integer> l= new LinkedList<>();
l.add(dest);
map.put(src,l);
}
else{
LinkedList<Integer> l= map.get(src);
l.add(dest);
map.put(src,l);
}
}
//display the adjency list
void displayGraph(){
for(Map.Entry m: map.entrySet()){
System.out.println(m.getKey()+"-->"+m.getValue());
}
}
public static void main(String[] args) {
Graph g= new Graph();
g.addEdge(0,1);
g.addEdge(0,4);
g.addEdge(0,5);
g.addEdge(1,4);
g.addEdge(1,3);
g.addEdge(3,2);
g.addEdge(2,1);
g.addEdge(3,4);
g.displayGraph();
}
}
Output:
0-->[1, 4, 5]
1-->[4, 3]
2-->[1]
3-->[2, 4]

Related

How to get random string value without duplicate?

I want to fetch only a single company name and I want to fetch it only once. So if it already was fetched, it should not be fetched again.
Here is the code:
private static String[] billercompanies = {
"1st",
"TELUS Communications",
"Rogers Cablesystems",
"Shaw Cable",
"TELUS Mobility Inc",
"Nanaimo Regional District of",
"Credit Union MasterCard",
};
public static String GetBillerCompany(){
String randomBillerComp = "";
randomBillerComp = (billercompanies[new Random().nextInt(billercompanies.length)]);
return randomBillerComp;
}
Just shuffle the array you want using Collections
Collections.shuffle(List);
So simply create a list from your array
List<E> list = Arrays.asList(array);
Then shuffle it using the method above
Collections.shuffle(list);
Your list can be read from left to right as it was random.
So simply save the index
int currentIndex = 0;
public E getRandom(){
//If at the end, start over
if(++currentIndex == list.size()) {
currentIndex = 0;
shuffle(list);
}
return list.get(currentIndex);
}
Each time you want to forget the duplicate list you already used, simply shuffle the array again
Collections.shuffle(list);
Without index
You could simply remove the first value each time, once the list is empty, recreate it with the original array. As Ole V.V. pointer out, a List generated by Arrays.asList(E[]) doesn't support the remove methods so it is necessary to generate a new instance from it.
Here is a quick and simple class using this solution :
public class RandomList<E>{
E[] array;
List<E> list;
public RandomList(E[] array){
this.array = array;
buildList(array);
}
public E getRandom(){
if(list.isEmpty()) buildList(array);
return list.remove(0);
}
public void buildList(E[] array){
list = new ArrayList<E>(Arrays.asList(array));
Collections.shuffle(list);
}
}
And the test was done with this small code :
Integer[] array = {1,2,3,4,5};
RandomList<Integer> rl = new RandomList(array);
int i = 0;
while(i++ < 10)
System.out.println(rl.getRandom());
Make a copy in a List and remove the element when it was already fetched.
Arrays.asList(array) is not modifiable but you can wrap it in a full featured List.
List<String> billercompaniesList = new ArrayList<>(Arrays.asList(billercompanies));
String randomBillerComp = "";
Random random = new Random();
// first retrieval
int index = random.nextInt(billercompaniesList.size());
randomBillerComp = billercompaniesList.get(index);
billercompaniesList.remove(index);
// second retrieval
index = random.nextInt(billercompaniesList.size());
randomBillerComp = billercompaniesList.get(index);
billercompaniesList.remove(index);
// and so for

setting a comparator for PriorityQueue(node) in Java

If I have a node with two data variables.
Say
class HuffNode{
public char iData;
public int frequency;
public HuffNode leftChild;
public HuffNode rightChild;
// ---------------------------------------------------------
HuffNode(char d){
this.iData = d;
this.frequency = 0;
}
}
Then, I want to put them in ascending order into a priority que by each Node's frequency.
PriorityQueue<HuffNode> q = new PriorityQueue<HuffNode>();
Set<Character>keys = map.keySet(); //iterator
Iterator<Character> it = keys.iterator();
while(it.hasNext()){
char key = it.next();
HuffNode node = new HuffNode(key);
node.frequency = map.get(key);
q.add()// want to add by frequency
}
If I just add the nodes into the que, I think the nodes will end up in an alphabetical order. How can I change the comparator to the frequency ?
thank you in advance.
Pass a Comparator as a constructor parameter, e.g.
new PriorityQueue<>(
initialCapacity,
new Comparator<HuffNode>() {
#Override public int compare(HuffNode a, HuffNode b) {
return Integer.compare(a.frequency, b.frequency);
}
});
Note that you don't really want the thing you are using to order the nodes to be mutable, especially if it is public - if you were to change the frequency value, it wouldn't automatically reorder in the queue.
You'd be well-served making as many fields as possible final.

The implementation of Map implies that each key may contains only 1 value... But i need that 1 key could store <Any Big Number> values

For example... Adjacency list realiszation
public class Vertex {
String name;
boolean visited;
public Vertex(String name) {
this.name=name;
visited=false;
}
public int hashCode() {
return name.hashCode();
}
public boolean equals(Object ob) {
return hashCode()==ob.hashCode();
}
public String toString() {
return name;
}
}
The main class
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) {
PrintWriter pw=new PrintWriter(System.out);
Map<Vertex,Vertex> m=new HashMap();
m.put(new Vertex("a"), new Vertex("b"));// a ---> b
m.put(new Vertex("a"), new Vertex("c"));// a ---> c
m.put(new Vertex("a"), new Vertex("d"));// a ---> d
pw.println("All vertex from: ");
for (Vertex vert_from:m.keySet()) {
pw.print(vert_from+" ");
}
pw.println();
pw.println("All vertices to: ");
for (Vertex vert_to:m.values()) {
pw.print(vert_to+" ");
}
pw.close();
}
}
It outputs:
All vertex from:
a
All vertices to:
d
But i need that "All vertices to: b c d"
How can I fix that?
A Map indeed stores a single value per key. You could, however, store a collection in value, say a Set:
Map<Vertex, Set<Vertex>> m = new HashMap<>();
Set<Vertex> set = new HashSet<>();
set.add(new Vertex("b"));
set.add(new Vertex("c"));
set.add(new Vertex("d"));
m.add (new Vertex("a"), set);
Alternatively, you can use one of the common implementations of this concept, such as Apache Commons Collections' MultiValueMap or Guava's HashMultiMap.
What you are asking for is called a "Multi Map".
If you are using Java 8 then this is quite neat, first you need a Map<Vertex, Collection<Vertex>>. I don't know what properties you need from the Collection, that you will have to investigate yourself.
As you have overridden equals and hashCode (incorrectly, but a valiant attempt), I will assume that you want to have the items unique by name. I will also assume that order matters, so LinkedHashSet seems a good choice.
final Map<Vertex, Collection<Vertex>> graph = new HashMap<>();
Now, to add an item to the Map we need to first ensure that the Collection for that key is not null. This is exactly what the new Map.computeIfAbsent comes in.
final Vertex a = new Vertex("a");
graph.computeIfAbsent(a, v -> new LinkedHashSet<>()).add(new Vertex("b"));
graph.computeIfAbsent(a, v -> new LinkedHashSet<>()).add(new Vertex("c"));
graph.computeIfAbsent(a, v -> new LinkedHashSet<>()).add(new Vertex("d"));
So what this does is, when inserting a into the Map, if the Collection for that key is null, computes a new value for it.
Now to get all values for a key:
Collection<Vertex> values = graph.get(a);
You could wrap the Map<Vertex, Collection<Vertex>> in some sort of Graph class to hide the implementation details and to have neater code:
class Graph {
final Map<Vertex, Collection<Vertex>> graph = new HashMap<>();
public void put(final Vertex key, final Vertex value) {
graph.computeIfAbsent(key, k -> new LinkedHashSet<>()).add(value);
}
public Collection<Vertex> get(final Vertex key) {
return Optional.ofNullable(graph.get(key)).orElse(Collections.EMPTY_SET);
}
}
This also deals with returning an empty collection instead of null if a key is not present in the Map. Depending on your use case you might also want to wrap the returned Collection with Collections.unmodifiableCollection to prevent unwanted modifications:
public Collection<Vertex> get(final Vertex key) {
return Optional.ofNullable(graph.get(key))
.map(Collections::unmodifiableCollection)
.orElse(Collections.EMPTY_SET);
}
You could also use a Guava Multimap if you aren't averse to external libraries.
Using a Multimap for your problem, it could be written like that:
public static void main(String[] args) {
PrintWriter pw=new PrintWriter(System.out);
ListMultimap<Vertex,Vertex> m= ArrayListMultimap.create();
Vertex a = new Vertex("a"); // it's better to create each object once
Vertex b = new Vertex("b");
Vertex c = new Vertex("c");
Vertex d = new Vertex("d");
m.put(a,b);// a ---> b
m.put(a,c);// a ---> c
m.put(a,d);// a ---> d
pw.println("All vertex from: ");
for (Vertex vert_from:m.keySet()) { //exactly the same as in your code
pw.print(vert_from+" ");
}
pw.println();
pw.println("All vertices to: ");
for (Vertex vert_to:m.values()) { //exactly the same as in your code
pw.print(vert_to+" ");
}
pw.close();
}
To use Guava, just download the latest jar from here and add it to your libraries.
Explanation:
By definition, each java Map has a single key and a single value.
However, you can use a Collection (like a List), or an Array for value. This way, your Map will be defined like that:
Map<Vertex, List<Vertex>> m = new HashMap<>();
Each time you want to add an element value to the list of vertex key, you can do it that way:
List<Vertex> list = m.get(key);
if (list == null) {
list = new ArrayList<>();
}
list.add(value);
An easier way, is to use Guava's Multimaps. It is the same as a Map, but the value is a Collection. So, an ArrayListMultimap is quite what I described above. The way to use it, though is much simpler:
ListMultimap<Vertex, Vertex> m = ArrayListMultimap.create();
m.put(key, value1);
m.put(key, value2); //adds value2 to the key, which also contains value1
....

Connect linkedList in java [duplicate]

This question already has answers here:
Java Beginner: How do I link one linked list to another?
(6 answers)
Closed 8 years ago.
I hava list of LinkedList and I want to make (unable to modified) One connected LinkedList .
and not change the original linkedLists.
LinkedLists<String> a=new LinkedList<String>();
LinkedLists<String> b=new LinkedList<String>();
LinkedLists<String> c=new LinkedList<String>();
a.add("as");
a.add("sa");
a.add("bb");
b.add("as");
b.add("sa");
c.add("bb");
c.add("d");
c.add("ya");
the new LinkedList contain ya d bb sa as bb sa as
so I want to make one Linked List.I preffer Not copy the items casue this consume memory.
Only connect theme for go all over the items not to modified the items.
Thanks!
Try Collections#unmodifiableList()
Sample code:
LinkedList<String> a = new LinkedList<String>();
a.add("as");
a.add("sa");
a.add("bb");
a.add("as");
a.add("sa");
a.add("bb");
a.add("d");
a.add("ya");
List<String> b = Collections.unmodifiableList(a.subList(0, 3));
List<String> c = Collections.unmodifiableList(a.subList(5, 8));
b.set(0, "aa"); // not allowed
c.add("zz"); // not allowed
a.set(6, "zz"); // allowed and List c is also updated.
Try subclassing List. Here's a quick example I put together below. It's largely incomplete but you'll get the idea.
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
public class Experiment {
public static void main(String[] args) throws Exception {
LinkedList<String> a = new LinkedList<String>();
LinkedList<String> b = new LinkedList<String>();
LinkedList<String> c = new LinkedList<String>();
a.add("as");
a.add("sa");
a.add("bb");
b.add("as");
b.add("sa");
c.add("bb");
c.add("d");
c.add("ya");
MyLinkedList<String> list = new MyLinkedList<String>();
list.add(a);
list.add(b);
list.add(c);
for (String s : list) {
System.out.println(s);
}
}
private static class MyLinkedList<T> extends LinkedList<T> {
private List<List<T>> lists = new LinkedList<List<T>>();
public void add(LinkedList<T> list) {
lists.add(list);
}
#Override
public Iterator<T> iterator() {
return new MyLinkedIterator<T>(lists);
}
}
private static class MyLinkedIterator<T> implements Iterator<T> {
private List<List<T>> lists;
private int listIndex = 0;
private int currentIndex = 0;
private T next;
public MyLinkedIterator(List<List<T>> lists) {
this.lists = lists;
}
public boolean hasNext() {
if (listIndex >= lists.size()) return false;
List<T> list = lists.get(listIndex);
if (currentIndex >= list.size()) {
currentIndex = 0;
listIndex++;
return hasNext();
}
next = list.get(currentIndex++);
return true;
}
public T next() {
return next;
}
public void remove() {
}
}
}
How about this:
LinkedList<String> a=new LinkedList<String>();
LinkedList<String> b=new LinkedList<String>();
LinkedList<String> c=new LinkedList<String>();
a.add("as");
a.add("sa");
a.add("bb");
b.add("as");
b.add("sa");
c.add("bb");
c.add("d");
c.add("ya");
LinkedList<String> unionList = new LinkedList<String>();
unionList.addAll(a);
unionList.addAll(b);
unionList.addAll(c);
LinkedList<String> unmodifiableUnion = Collections.unmodifiableList(unionList);
It uses addAll() to add all lists into a new one and returns an unmodifiable list from it using Collections.unmodifiableList()
Update
If memory consumption is your problem, the standard JDK is not enough. You will have to implement your own or use an existing one.
To implement your own you can usa a LinkedList<List<T>> to store your linked lists and implement the List interface. mprivat started an implementation for you.
To use an existing one, you could use:
Trove: it is considered really good and fast if no fastest with least memory consumption, at least that is what I have observed in my usages of it.
this implementation: it is a singly linked list so it consumes less memory and has a merge method that will merge 2 linked lists using their "pointers" as you would expect.

array element as linkedlist in java

I have an home work,I used an array and element of array is linked list because the element in a row is not fixed need delete or add some time depend on problem condition , I was tried these codes below, but I have a problem when adding new element to a fixed row for example p[0] the value will be added for all, how I can solve this problem please help.
public class schedule
{
public class link
{
public LinkedList <Integer>list = new LinkedList<Integer>() ;
public link(LinkedList<Integer> value)
{
list = value;
}
public link(int value)
{
list.add(Integer.valueOf(value)) ;
}
}
private link p[] = new link[10];
public schedule()
{
LinkedList<Integer> l = new LinkedList<Integer>();
l.add(Integer.valueOf(2));
l.add(Integer.valueOf(0));
l.add(Integer.valueOf(3));
for(int j=0;j<p.length;j++)
p[j] = new link(l);
p[0].list.add(9); // here I have problem
for(int j=0;j<p.length;j++)
{
System.out.print("p["+j+"]:");
for(int i=0;i<p[j].list.size();i++)
System.out.print(p[j].list.get(i).intValue());
System.out.println();
}
}
public static void main(String []arg)
{
new schedule();
}
the output is like this : the value 9 added to all but I want to be added just for first element
p[0]:2039
p[1]:2039
p[2]:2039
p[3]:2039
p[4]:2039
p[5]:2039
p[6]:2039
p[7]:2039
p[8]:2039
p[9]:2039
The problem is that you're initializing every link instance with the same LinkedList<Integer>:
LinkedList<Integer> l = new LinkedList<Integer>();
l.add(Integer.valueOf(2));
l.add(Integer.valueOf(0));
l.add(Integer.valueOf(3));
for(int j=0;j<p.length;j++)
//it will be the same LinkedList<Integer> l per all the instances in the array
p[j] = new link(l);
Take note that when you do this, every link instance will have the list attribute referencing the same LinkedList<Integer> l variable. So, if you modify it in one place, everyone will be updated (because it's the same reference).
There are many ways to solve this:
Create a new LinkedList on every iteration of your for loop.
Create the new link instance using another constructor.
Fill your link[] p array one by one...

Categories

Resources