All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.specs2.data.HopcroftKarp.scala Maven / Gradle / Ivy

The newest version!
package org.specs2
package data

import scala.collection.mutable

/**
 * Hopcroft-Karp (https://en.wikipedia.org/wiki/Hopcroft%E2%80%93Karp_algorithm) algorithm for
 * finding the maximum matching in a bipartite graph
 *
 * This is used for "contain" matchers to find the best matches between actual and expected elements in 2 lists
 *
 */
object HopcroftKarp {

  def findMaximalMatching(vertex1: Seq[Int], vertex2: Seq[Int], edges: Map[Int, Seq[Int]]): List[(Int, Int)] = {
    val nil = -1
    val queue: mutable.Queue[Int] = new mutable.Queue[Int]
    val dist: mutable.Map[Int, Int] =  new mutable.HashMap[Int, Int]
    val pair1: mutable.Map[Int, Int] = new mutable.HashMap[Int, Int]
    val pair2: mutable.Map[Int, Int] = new mutable.HashMap[Int, Int]

    def bfs: Boolean = {
      vertex1.foreach { v =>
        if (pair1(v) == nil) {
          dist.put(v, 0)
          queue.enqueue(v)
        } else dist.put(v, Int.MaxValue)
      }
      dist.put(nil, Int.MaxValue)

      while (queue.nonEmpty) {
        val v = queue.dequeue

        if (dist(v) < dist(nil)) {
          edges.get(v).toSeq.flatten.foreach { u =>
            if (dist(pair2(u)) == Int.MaxValue) {
              dist.put(pair2(u), dist(v) + 1)
              queue.enqueue(pair2(u))
            }
          }
        }
      }
      dist(nil) != Int.MaxValue
    }

    def dfs(v: Int): Boolean = {
      if (v != -1) {
        edges.get(v).toSeq.flatten.foreach { u =>
          if (dist(pair2(u)) == dist(v) + 1 && dfs(pair2(u))) {
            pair2.put(u, v)
            pair1.put(v, u)
            return true
          }
        }
        dist.put(v, Int.MaxValue)
        false
      } else true
    }

    ((vertex1 ++ vertex2) :+ nil).foreach { v =>
      pair1.put(v, nil)
      pair2.put(v, nil)
    }
    var matching = 0
    while (bfs) {
      vertex1.foreach { v =>
        if (pair1(v) == nil && dfs(v))
          matching = matching + 1
      }
    }
    pair1.toList.filterNot(_._2 == nil)
  }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy