优化这个ruby代码,将数组切换到sets / hash?

时间:2011-08-09 20:35:05

标签: ruby arrays optimization hash set

我需要优化此代码。有任何建议让它变得更快,请告诉我。我没有特定的数量,我希望它更快,任何建议都会有所帮助。就复杂性而言,我希望将其保持在O(n ^ 2)

以下

我想知道是否尝试将我正在使用的数组转换为set或hash,因为这样更快?在复杂性方面,这可以让我运行多快?

我认为主要的问题可能是我使用的ruby组合函数运行速度很慢,有没有人确切知道这个ruby函数的复杂性?有更快的替代方案吗?

这段代码的重点基本上是找到与所有其他点的最短组合距离的单点,即(每个人最方便的朋友家)。这里有一些额外的代码,它有一些调试/打印功能。

class Point
    attr_accessor :x, :y, :distance, :done, :count

    def initialize(x,y)
        @x = x
        @y = y
        @distance = 0
        @closestPoint = []
        @done = false
        @count = 0
    end
end

class Edge
    attr_accessor :edge1, :edge2, :weight

    def initialize(edge1,edge2,weight)
      @edge1 = edge1
      @edge2 = edge2
      @weight = weight
    end
end

class AdjacencyList
    attr_accessor :name, :minSumList, :current

    def initialize(name)
      @name = name
      @minSumList = []
      @current = nil
      @vList = []
      @edgeList = []
    end

    def addVertex(vertex)
      @vList.push(vertex)
    end

    def generateEdges2
      minSumNode = nil
      current = nil
      last = nil

      @vList.combination(2) { |vertex1, vertex2|
        distance = distance2points(vertex1,vertex2)
        edge = Edge.new(vertex1,vertex2,distance)

        if (current == nil)
          current = vertex1
          minSumNode = vertex1
        end

        vertex1.distance += distance
        vertex2.distance += distance

        vertex1.count += 1
        vertex2.count += 1

        if (vertex1.count == @vList.length-1)
          vertex1.done = true
        elsif (vertex2.count == @vList.length-1)
           vertex2.done = true
        end

        if ((vertex1.distance < minSumNode.distance) && (vertex1.done == true))            
          minSumNode = vertex1
        end

        #@edgeList.push(edge)
       }

        return minSumNode.distance
    end

    def generateEdges
      @vList.combination(2) { |vertex1, vertex2| 
        distance = distance2points(vertex1,vertex2)
        @edgeList.push(Edge.new(vertex1,vertex2,distance))
      }
    end

    def printEdges
      @edgeList.each {|edge| puts "(#{edge.edge1.x},#{edge.edge1.y}) <=> (#{edge.edge2.x},#{edge.edge2.y}) weight: #{edge.weight}"}
    end

    def printDistances
      @vList.each {|v| puts "(#{v.x},#{v.y} distance = #{v.distance})"}
    end
end

def distance2points(point1,point2)
     xdistance = (point1.x - point2.x).abs
     ydistance = (point1.y - point2.y).abs

     total_raw = xdistance + ydistance
     return totaldistance = total_raw - [xdistance,ydistance].min
end

#pointtest1 = Point.new(0,1)
#pointtest2 = Point.new(2,5)
#pointtest3 = Point.new(3,1)
#pointtest4 = Point.new(4,0)

graph = AdjacencyList.new("graph1")

gets
while (line = gets)
    graph.addVertex(Point.new(line.split[0].to_i,line.split[1].to_i))
end

#graph.addVertex(pointtest1)
#graph.addVertex(pointtest2)
#graph.addVertex(pointtest3)
#graph.addVertex(pointtest4)

puts graph.generateEdges2
#graph.printEdges
#graph.printDistances

3 个答案:

答案 0 :(得分:2)

尝试执行此操作,然后发布更多代码:

ruby -rprofile your_script your_args

这将在探查器下运行脚本,并生成一个包含结果的漂亮表。如果您在此处发布,则更有可能获得更好的帮助。此外,您将更准确地了解消耗CPU周期的因素。

答案 1 :(得分:1)

集合基本上是哈希值,散列优于数组的优点是O(1)查找操作。由于您只是遍历整个数组,如果只是用散列替换数组,散列将不会提供任何速度提升。

你真正的问题是你的算法的运行时间是O(n ^ 2),因为给定一组n个点它将必须执行n ^ 2个操作,因为你将每个点与其他每个点匹配点。

使用哈希缓存值可以稍微改善一下。例如,假设您想要点“a”和点“b”之间的距离。您可以使用存储@distances的哈希@distances["a,b"] = 52(当然,您必须明智地知道要使用什么作为密钥)。基本上只是尝试在任何地方删除冗余操作。

也就是说,最大的速度提升将来自更智能的算法,但我现在无法想到一些适用的东西。

答案 2 :(得分:0)

有很多人都知道的东西,它不会让你付出任何代价。

当您试图猜测如何使代码更快,或者在互联网上搜索某种类型的分析器时,只需在调试器下运行该程序并在它缓慢时中断它。

多次这样做,每次都要仔细记录它正在做什么以及为什么。

Here's an example in python.

越慢,问题就越明显。