package com.interview.graph;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Graph<T>{
private List<Edge<T>> allEdges;
private Map<Long,Vertex<T>> allVertex;
boolean isDirected = false;
public Graph(boolean isDirected){
allEdges = new ArrayList<Edge<T>>();
allVertex = new HashMap<Long,Vertex<T>>();
this.isDirected = isDirected;
}
public void addEdge(long id1, long id2){
addEdge(id1,id2,0);
}
//This works only for directed graph because for undirected graph we can end up
//adding edges two times to allEdges
public void addVertex(Vertex<T> vertex){
if(allVertex.containsKey(vertex.getId())){
return;
}
allVertex.put(vertex.getId(), vertex);
for(Edge<T> edge : vertex.getEdges()){
allEdges.add(edge);
}
}
public Vertex<T> addSingleVertex(long id){
if(allVertex.containsKey(id)){
return allVertex.get(id);
}
Vertex<T> v = new Vertex<T>(id);
allVertex.put(id, v);
return v;
}
public Vertex<T> getVertex(long id){
return allVertex.get(id);
}
public void addEdge(long id1,long id2, int weight){
Vertex<T> vertex1 = null;
if(allVertex.containsKey(id1)){
vertex1 = allVertex.get(id1);
}else{
vertex1 = new Vertex<T>(id1);
allVertex.put(id1, vertex1);
}
Vertex<T> vertex2 = null;
if(allVertex.containsKey(id2)){
vertex2 = allVertex.get(id2);
}else{
vertex2 = new Vertex<T>(id2);
allVertex.put(id2, vertex2);
}
Edge<T> edge = new Edge<T>(vertex1,vertex2,isDirected,weight);
allEdges.add(edge);
vertex1.addAdjacentVertex(edge, vertex2);
if(!isDirected){
vertex2.addAdjacentVertex(edge, vertex1);
}
}
public List<Edge<T>> getAllEdges(){
return allEdges;
}
public Collection<Vertex<T>> getAllVertex(){
return allVertex.values();
}
public void setDataForVertex(long id, T data){
if(allVertex.containsKey(id)){
Vertex<T> vertex = allVertex.get(id);
vertex.setData(data);
}
}
@Override
public String toString(){
StringBuffer buffer = new StringBuffer();
for(Edge<T> edge : getAllEdges()){
buffer.append(edge.getVertex1() + " " + edge.getVertex2() + " " + edge.getWeight());
buffer.append("\n");
}
return buffer.toString();
}
}
class Vertex<T> {
long id;
private T data;
private List<Edge<T>> edges = new ArrayList<>();
private List<Vertex<T>> adjacentVertex = new ArrayList<>();
Vertex(long id){
this.id = id;
}
public long getId(){
return id;
}
public void setData(T data){
this.data = data;
}
public T getData(){
return data;
}
public void addAdjacentVertex(Edge<T> e, Vertex<T> v){
edges.add(e);
adjacentVertex.add(v);
}
public String toString(){
return String.valueOf(id);
}
public List<Vertex<T>> getAdjacentVertexes(){
return adjacentVertex;
}
public List<Edge<T>> getEdges(){
return edges;
}
public int getDegree(){
return edges.size();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (id ^ (id >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Vertex other = (Vertex) obj;
if (id != other.id)
return false;
return true;
}
}
class Edge<T>{
private boolean isDirected = false;
private Vertex<T> vertex1;
private Vertex<T> vertex2;
private int weight;
Edge(Vertex<T> vertex1, Vertex<T> vertex2){
this.vertex1 = vertex1;
this.vertex2 = vertex2;
}
Edge(Vertex<T> vertex1, Vertex<T> vertex2,boolean isDirected,int weight){
this.vertex1 = vertex1;
this.vertex2 = vertex2;
this.weight = weight;
this.isDirected = isDirected;
}
Edge(Vertex<T> vertex1, Vertex<T> vertex2,boolean isDirected){
this.vertex1 = vertex1;
this.vertex2 = vertex2;
this.isDirected = isDirected;
}
Vertex<T> getVertex1(){
return vertex1;
}
Vertex<T> getVertex2(){
return vertex2;
}
int getWeight(){
return weight;
}
public boolean isDirected(){
return isDirected;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((vertex1 == null) ? 0 : vertex1.hashCode());
result = prime * result + ((vertex2 == null) ? 0 : vertex2.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Edge other = (Edge) obj;
if (vertex1 == null) {
if (other.vertex1 != null)
return false;
} else if (!vertex1.equals(other.vertex1))
return false;
if (vertex2 == null) {
if (other.vertex2 != null)
return false;
} else if (!vertex2.equals(other.vertex2))
return false;
return true;
}
@Override
public String toString() {
return "Edge [isDirected=" + isDirected + ", vertex1=" + vertex1
+ ", vertex2=" + vertex2 + ", weight=" + weight + "]";
}
}