Friday, October 3, 2014

Coursera quick-union

I have recently made another attempt at taking Coursera's Algorithms course. At the moment I am not in an urgent need to optimize my programs and estimate their efficiency as my programs are quite small, but the day will hopefully come and I will need this knowledge. Anyway, I tried taking this course some time ago but dropped out of due to the lack of time. Hence, attempt number 2.

I started a little late and only covered week 1 materials for now. Week 1 problems cover quick-union algorithms. Even though the course is taught in Java, I decided to re-write the weighted quick-union algorithm in Ruby (it didn't look that much different from the original). I further applied it to the following proposed problem: Given a social network containing N members and a log file containing M timestamps at which times pairs of members formed friendships, design an algorithm to determine the earliest time at which all members are connected (i.e., every member is a friend of a friend of a friend ... of a friend). Assume that the log file is sorted by timestamp and that friendship is an equivalence relation.

I interpret this problem such that we should determine how many friend groups are in there. If there is only one friend group, this means all people are connected to each other, and we return the timestamp associated with the last node.

We start with the total number of nodes equal to the number of connections, and as we loop through friend pairs and merge them into groups, we reduce the number of nodes by 1. At the end, we should be left with one node only.

sample input:
20141001 0 2
20141002 0 4
20141003 2 3
....

class WeightedQuickUnionUF

    attr_reader :total_roots

    def initialize(n)
        @id = (0...n).to_a
        @sz = (0...n).to_a
        @total_roots = n
    end

    def connected?(first, second)
        find(first) == find(second)
    end

    def friends_connected?
        @total_roots == 1
    end

    def union(first, second)
        i = find(first)
        j = find(second)

        return if i == j

        if @sz[i] < @sz[j]
            @id[i] = j
            @sz[j] += @sz[i]
        else
            @id[j] = i
            @sz[i] += @sz[j]
        end
        @total_roots -= 1
    end

    def show
        print "#{@id}\n"
    end

    def find(index)
        while index != @id[index]
            index = @id[index]
        end
        index
    end

end

test = WeightedQuickUnionUF.new(13)

f = File.open("links.txt", "r")
f.each_line do |line|
    l = line.split(' ')
    test.union(l[1].to_i,l[2].to_i)
    print "#{l[0]}: #{test.friends_connected?} #{test.total_roots}\n"
end
f.close

No comments :

Post a Comment