Algorithm notes - graph, graph definition method, graph width first traversal BFS, depth first traversal DFS, topological sorting algorithm, K algorithm, P algorithm, dijestra algorithm

1, The storage method of the graph. If the graph is expressed, the graph is generated

1. Storage mode of drawing

  • Adjacency table

  • adjacency matrix

2. Expression of graph - point set, edge set, graph

  • point set
public class Node {
        	public int value;
        	public int in; //Penetration
        	public int out; //Out degree
        	public ArrayList<Node> nexts;  //The point of a direct neighbor diverged by him
        	public ArrayList<Edge> edges;  //What are my sides

        	public Node(int value) {
        		this.value = value;
        		in = 0;
        		out = 0;
        		nexts = new ArrayList<>();
        		edges = new ArrayList<>();
        	}
        }
  • Edge set
public class Edge {
        	public int weight; //weight
        	public Node from;  //Directed edge from
        	public Node to;  //Directed edge to

        	public Edge(int weight, Node from, Node to) {
        		this.weight = weight;
        		this.from = from;
        		this.to = to;
        	}

        }
  • Figure: Point Set + edge set
public class Graph {
     public HashMap<Integer,Node> nodes; // The Integer here represents a marker value of the point that appears
     public HashSet<Edge> edges;  //Edge set

     public Graph() {
        nodes = new HashMap<>();
        edges = new HashSet<>();
     }
}

3. Generate diagram

  • Two dimensional array, in which the first item of each array represents the weight and the second item represents from. The third item indicates to
        public static Graph createGraph(Integer[][] matrix) {
        		Graph graph = new Graph();
        		//The outermost loop represents several large loops, one one-dimensional array and one edge at a time
        		for (int i = 0; i < matrix.length; i++) {
        			//The first item in each array represents the weight
        			Integer weight = matrix[i][0];
        			//The second item indicates where from comes from
        			Integer from = matrix[i][1];
        			//The third item indicates where to points
        			Integer to = matrix[i][2];
        			//Judge this first. If not, skip it
        			//If the from point does not exist in the point set of the graph, add the point to the point set
        			//Update of point set of graph
        			if (!graph.nodes.containsKey(from)) {
        				graph.nodes.put(from, new Node(from));//join
        			}
        			//If the to point does not exist in the point set of the graph, add the point to the point set
        			if (!graph.nodes.containsKey(to)) {
        				graph.nodes.put(to, new Node(to));//join
        			}
        			//Get the from point and the to point
        			Node fromNode = graph.nodes.get(from);
        			Node toNode = graph.nodes.get(to);
        			//The edges are established by these two points and weights
        			Edge newEdge = new Edge(weight, fromNode, toNode);
        			//Next, you need to update: points, edges and graphs should be updated
        			//Update the nexts of fromnode's points, that is, the points of direct neighbors diverged by him
        			fromNode.nexts.add(toNode);
        			//Update the out of the fromnode point, that is, the out degree++
        			fromNode.out++;
        			//Update the in of the point of tonode, that is, the penetration++
        			toNode.in++;
        			//Update the edges of fromnode, that is, update the edges belonging to fromnode. This is to add a newly created edge
        			fromNode.edges.add(newEdge);
        			//Graph update, add one more edge set
        			graph.edges.add(newEdge);
        		}
        		return graph;
        	}

2, Traversal of Graphs

1. The width of the drawing shall first traverse the BFS

Using queues to implement
Enter the queue according to the width from the source node, and then pop up;
For each pop-up point, put all adjacent points of the node that have not entered the queue into the queue;
Until the queue is empty.

//Only point set type is needed
public void BFS_(Node node){
	if(node == null){
		return;
	}
	//Prepare a queue to pop up by width in turn
	Queue<Node> queue = new LinkedList<>();
	//Prepare a set set for de duplication to prevent a node from being added to the queue repeatedly, and finally output such errors repeatedly
	HashSet<Object> hashset = new HashSet<>();
	//First add the source node to set and queue
	queue.add(node);
	hashset.add(node);
	//If the queue is not empty, it pops up one by one
	while(!queue.isEmpty()){
		Node cur = queue.poll();
		//Output on pop-up
		System.out.println(cur.value);
		//During each pop-up, all adjacent nodes of the pop-up node and nodes that have not entered the set are added to the queue.
		for(Node next:cur.nexts){
			if(!hashset.contains(next)){
				hashset.add(next);
				queue.add(next);
			}
		}
	}
}

2. The depth of the graph first traverses DFS

Depth first traversal: starting from the initial access point, the initial access point may have multiple adjacent nodes. The strategy of depth first traversal is to first access the first adjacent node, and then use the accessed adjacent node as the initial access node to access its first adjacent node, That is, each time the current node is accessed, the first adjacent node of the current node will be accessed first. Similar to maze backtracking algorithm.
It can be seen that the current access strategy is to give priority to vertical mining, rather than horizontal access to all adjacent points of each node.

Using stack
A single wooden bridge goes to the black
Start from the source node, put each node into the stack according to the depth, and then pop up;
For each pop-up point, put the next adjacent point of the node that has not entered the stack into the stack;
Until the stack becomes empty.

public void DFS_(Node head){
	HashSet<Node> hashset = new HashSet<>();
	Stack<Node> stack = new Stack<>();
	stack.push(node);
	hashset.add(node);
	System.out.println(node.value);
	while(!stack.isEmpty()){
		Node cur = stack.pop();
		for(Node next : cur.nexts){
			if(!hashset.contains(next)){
				//Note here that cur itself should also be added. Why? This gives a way back to prevent the next encounter from already in the set, so we have to find a way back, that is, backtracking and find other nodes.
				stack.push(cur);
				stack.push(next);
				hashset.add(next);
				System.out.println(next.value);
				//The reason for breaking is to let him not follow the width, but encounter a cycle of breaking this time, and let him continue down the new node. If he doesn't break, go to the width.
				break;
			}	
		}
	}	
}

3, Topological sorting algorithm

Scope of application: it is required to have a directed graph, nodes with penetration of 0, and no ring
Topological sorting is actually to find a vertex with a degree of 0. This vertex is the first vertex sequence in topological sorting, mark and delete it, then reduce the degree of entry of the vertex adjacent to this vertex by 1, and then continue to find the vertex with a degree of 0 until all vertices have been marked and deleted or there are rings in the graph.
It can be seen from the above that the key is to find the vertex with penetration of 0.

Dependency completion sort
Directed graph
Using hash table
Find the points with penetration of 0 in turn, wipe them off in turn, and find them again in turn

	public static List<Node> sortTopology(Graph graph){
        //K of hashmap represents a node, and V represents the remaining penetration
        HashMap<Node, Integer> hashMap = new HashMap<>();
        //Points with 0 remaining in the queue enter the queue
        Queue<Node> zeroInQueue = new LinkedList<>();
        for (Node node : graph.nodes.values()){
            hashMap.put(node, node.in); // Record the original penetration
            if (node.in == 0){ // The first batch of click in queues with a penetration of 0
                zeroInQueue.add(node);
            }
        }
        //The topology sorting results are placed in the result
        List<Node> result = new ArrayList<>();
        while ( !zeroInQueue.isEmpty()){
            Node cur = zeroInQueue.poll();
            result.add(cur);
            //Erase the influence of the current node
            for (Node next : cur.nexts){
                hashMap.put(next,hashMap.get(next) - 1); //Penetration is wiped
                if (hashMap.get(next) == 0){
                    zeroInQueue.add(next);
                }
            }
        }
        return result;
    }

4, Two algorithms of minimum spanning tree

Minimum spanning tree = = = guaranteed connectivity, minimum weight, for undirected graph

1.Kruskal algorithm

Scope of application: undirected graph is required

  • Algorithm overview

Kruskal algorithm can be referred to as "edge addition method".
1) Always start from the edge with the smallest weight and investigate the edge with the larger weight in turn
2) The current edge either enters the collection of the minimum spanning tree or is discarded
3) If the current edge enters the set of the minimum spanning tree and does not form a ring, the current edge is selected
4) If the current edge enters the set of the minimum spanning tree to form a ring, do not use the current edge
5) After examining all the edges, the set of the minimum spanning tree is also obtained.

  • sketch

1) To sort the edges, start from the smallest edge and judge whether there is an invisible ring (and search the set). If it is formed, it will not be added, and if it is not formed, it will be added
2) The judgment has an invisible ring, and all the initial points have a set respectively, which can be combined if possible.
3) Set query and merge - > join query set or common method

  • Common method
	public static class Mysets{

        public HashMap<Node, List<Node>> setMap;//map of the collection of points

        public Mysets(List<Node> nodes){
            for (Node cur: nodes){
                List<Node> set = new ArrayList<>(); // Collection of each point
                set.add(cur); //The collection of each point is its own at the beginning
                setMap.put(cur,set);
            }
        }

        //Are from and to in the same set
        public boolean isSameSet(Node from, Node to){
            List<Node> fromSet = setMap.get(from); //Collection from
            List<Node> toSet = setMap.get(to); //Set of to
            return fromSet == toSet; //Judge whether it is a set
        }

        //Synthesis of two sets
        public void union(Node from, Node to){
            List<Node> fromSet = setMap.get(from); //Collection from
            List<Node> toSet = setMap.get(to); //Set of to
            for (Node toNode : toSet){
                fromSet.add(toNode);
                setMap.put(toNode,fromSet);
            }
        }
    }
    //K algorithm
    public static Set<Edge> kruskalMST(Graph graph){
        Mysets mysets = new Mysets((List<Node>) graph.nodes.values());
        //At the bottom of the priority queue is the heap
        PriorityQueue<Edge> priorityQueue = new PriorityQueue<>(new Comparator<Edge>() {
            @Override
            public int compare(Edge o1, Edge o2) {
                return o1.weight - o2.weight;
            }
        });
        for (Edge edge : graph.edges){
            priorityQueue.add(edge);
        }
        Set<Edge> result = new HashSet<>();
        while ( !priorityQueue.isEmpty()){
            Edge edge = priorityQueue.poll();
            if ( !mysets.isSameSet(edge.from, edge.to)){
                result.add(edge);
                mysets.union(edge.from, edge.to);
            }
        }
        return result;
    }
  • Use and query set
// Union-Find Set
	public static class UnionFind {
		private HashMap<Node, Node> fatherMap;
		private HashMap<Node, Integer> rankMap;

		public UnionFind() {
			fatherMap = new HashMap<Node, Node>();
			rankMap = new HashMap<Node, Integer>();
		}

		private Node findFather(Node n) {
			Node father = fatherMap.get(n);
			if (father != n) {
				father = findFather(father);
			}
			fatherMap.put(n, father);
			return father;
		}

		public void makeSets(Collection<Node> nodes) {
			fatherMap.clear();
			rankMap.clear();
			for (Node node : nodes) {
				fatherMap.put(node, node);
				rankMap.put(node, 1);
			}
		}

		public boolean isSameSet(Node a, Node b) {
			return findFather(a) == findFather(b);
		}

		public void union(Node a, Node b) {
			if (a == null || b == null) {
				return;
			}
			Node aFather = findFather(a);
			Node bFather = findFather(b);
			if (aFather != bFather) {
				int aFrank = rankMap.get(aFather);
				int bFrank = rankMap.get(bFather);
				if (aFrank <= bFrank) {
					fatherMap.put(aFather, bFather);
					rankMap.put(bFather, aFrank + bFrank);
				} else {
					fatherMap.put(bFather, aFather);
					rankMap.put(aFather, aFrank + bFrank);
				}
			}
		}
	}

	public static class EdgeComparator implements Comparator<Edge> {

		@Override
		public int compare(Edge o1, Edge o2) {
			return o1.weight - o2.weight;
		}

	}

	public static Set<Edge> kruskalMST(Graph graph) {
		UnionFind unionFind = new UnionFind();
		unionFind.makeSets(graph.nodes.values());
		PriorityQueue<Edge> priorityQueue = new PriorityQueue<>(new EdgeComparator());
		for (Edge edge : graph.edges) {
			priorityQueue.add(edge);
		}
		Set<Edge> result = new HashSet<>();
		while (!priorityQueue.isEmpty()) {
			Edge edge = priorityQueue.poll();
			if (!unionFind.isSameSet(edge.from, edge.to)) {
				result.add(edge);
				unionFind.union(edge.from, edge.to);
			}
		}
		return result;
	}

2.Prim algorithm

Scope of application: undirected graph is required
Starting from the point, find the smallest edge, so as to get the point and start again and again

public static class EdgeComparator implements Comparator<Edge>{
        @Override
        public int compare(Edge o1, Edge o2) {
            return o1.weight - o2.weight;
        }
    }
    public static Set<Edge> primSet(Graph graph){
        //The unlocked edge enters the small root heap
        PriorityQueue<Edge> priorityQueue = new PriorityQueue<>(new EdgeComparator());
        HashSet<Node> set = new HashSet<>(); //The unlocked points are placed in the set
        Set<Edge> result = new HashSet<>(); //Select the edges in turn and put them into result
        //The for loop handles the forest problem and generates the minimum spanning tree respectively. This is a special case. If the whole is a connected graph, there is no need to add it here        
        for (Node node : graph.nodes.values()){//Pick any point
            //node is the starting point
            if ( !set.contains(node)){
                set.add(node);
                for (Edge edge : node.edgs){ //By one point, unlock all connected edges
                    priorityQueue.add(edge);
                }
                while ( !priorityQueue.isEmpty()){
                    Edge edge = priorityQueue.poll(); //The smallest of the pop-up unlocked edges
                    Node toNode = edge.to;
                    //Judge whether the toNode is a new point or not in the set
                    if ( !set.contains(toNode)){ //No, just a new point, just join
                        set.add(toNode);
                        //I want this side
                        result.add(edge);
                        //The edges diverged from the toNode are put into the priority queue
                        for (Edge nextEdge : toNode.edgs){
                            priorityQueue.add(nextEdge);
                        }
                    }
                }
            }
        }
        return result;
    }

5, Dijkstra algorithm

Scope of application: there are no edges with negative weight

Tags: Algorithm data structure kruskal Prim

Posted on Thu, 18 Nov 2021 06:25:47 -0500 by caaronbeasley