一个工作中的问题,同事写了程序解决。
问题:两组矩形,找出在另一组中有重叠的矩形。
故事的最初是同事提到Pyton版本的程序比Tcl版本的程序快上百倍。自己觉得中间一定有问题,于是研究了一下。
A single spark can start a prairie fire.
bbox = {$llx $lly $urx $ury} bbox_list = [$bbox_1, $bbox_2, ... , $bbox_n] sorted_bbox_list = sort bbox by $llx, $lly, $urx, $ury
版本 | 时间 (second) | 备注 |
---|---|---|
版本 0 | 403.097683 | |
版本 1 | 164.105524 | 函数内联 (inline function) |
版本 2 | 2.088276 | 跳头跳尾 |
版本 2-1 | 1.954031 | foreach 改为 for |
版本 3 | 0.382711 | Grid Cell |
版本 | 时间 (second) | 备注 |
版本 3-0 | 0.839178 | Grid Cell Size = 1000, 浮点数运算 |
版本 3-1 | 0.397401 | Grid Cell Size = 1000,整数运算 |
版本 3-2 | 0.342326 | Grid Cell Size = 256, 除法操作 |
版本 3-3 | 0.331954 | Grid Cell Size = 256, 移位操作 |
版本 | 时间 (second) | 备注 |
版本 3-0-0 | 1.125434 | Grid Cell Size = 1000, 浮点数运算,puts log |
版本 3-0-1 | 0.505042 | Grid Cell Size = 1000, 浮点数运算,no log |
版本 3-1-0 | 0.644948 | Grid Cell Size = 1000,整数运算, puts log |
版本 3-1-1 | 0.490211 | Grid Cell Size = 1000,整数运算, no log |
版本 | 时间 (second) | 备注 |
版本 4 | TODO | 四叉树算法 |
一些结论:
四叉树可以看作是动态大小的Grid Cell,并以Tree的方式进行检索。
Grid Cell方法则是固定的Grid Cell大小,借助hash table进行检索。
如果不能使用hash table的方法来检索,很可能需要一个sorted set来进行查询,或者用四叉树进行索引。
proc cmp_bbox {icv_bbox icc_bbox} { foreach {in1_x1 in1_y1 in1_x2 in1_y2} $icv_bbox break foreach {in2_x1 in2_y1 in2_x2 in2_y2} $icc_bbox break if {$in2_x1>=$in1_x2} { return -1 } elseif {$in2_x2<=$in1_x1 || $in2_y2<=$in1_y1 || $in2_y1>=$in1_y2} { return 0 } else { return 1 } } proc diff_bbox_list_0 {icv_bboxs icc_bboxs} { timer mark set i 0 foreach icv_bbox $icv_bboxs { incr i set found 0 set j 0 foreach icc_bbox $icc_bboxs { incr j set flag [cmp_bbox $icv_bbox $icc_bbox] if {$flag<0} { break } elseif {$flag==0} { continue } else { set found 1 } } puts "LUT COUNT: ($i $j) $found" } timer "end while" }
... foreach {in2_x1 in2_y1 in2_x2 in2_y2} $icc_bbox break if {$in2_x1>=$in1_x2} { break #return 2 } elseif {$in2_x2<=$in1_x1 || $in2_y2<=$in1_y1 || $in2_y1>=$in1_y2} { continue } else { set found 1 } ...
proc diff_bbox_list_2 {icv_bboxs icc_bboxs} { timer mark set list2_head 0 ... ... set max_urx -12345678 foreach icc_bbox $icc_bboxs { incr j if {$j<=$list2_head} continue foreach {in2_x1 in2_y1 in2_x2 in2_y2} $icc_bbox break set max_urx [expr {max($in2_x2,$max_urx)}] if {$max_urx<=$in1_x1} { set list2_head [expr {$j+1}] ;# SKIP all bbox outside left side } ... ... }
... for {set j $list2_head ; set n [llength $icc_bboxs]} {$j<$n} {incr j} { ... } ...
proc diff_bbox_list_3 {icv_bboxs icc_bboxs {max 0x7fffffff}} { timer mark set gcell_size 1000 set gcell_size $::env(GCELL_SIZE) ;# 1000 set i 0 foreach bbox $icv_bboxs { foreach {llx lly urx ury} $bbox break set gx1 [expr {int($llx/$gcell_size)}] ; set gy1 [expr {int($lly/$gcell_size)}] set gx2 [expr {int($urx/$gcell_size)}] ; set gy2 [expr {int($ury/$gcell_size)}] for {set gx $gx1} {$gx<=$gx2} {incr gx} { for {set gy $gy1} {$gy<=$gy2} {incr gy} { lappend gcells1($gx,$gy) $i } } incr i } timer "end grc 1" set i 0 foreach bbox $icv_bboxs { set icv_bbox $bbox foreach {llx lly urx ury} $bbox break set gx1 [expr {int($llx/$gcell_size)}]; set gy1 [expr {int($lly/$gcell_size)}] set gx2 [expr {int($urx/$gcell_size)}]; set gy2 [expr {int($ury/$gcell_size)}] set bbox_idxs "" for {set gx $gx1} {$gx<=$gx2} {incr gx} { for {set gy $gy1} {$gy<=$gy2} {incr gy} { foreach {gxy bboxs} [array get gcells2 "$gx,$gy"] break set bbox_idxs [concat $bbox_idxs $bboxs] } } set idxs [lsort -uniq $bbox_idxs] set j [llength $idxs] set found 0 set found_bbox {} foreach idx $idxs { set icc_bbox [lindex $icc_bboxs $idx] foreach {llx2 lly2 urx2 ury2} $icc_bbox break if {!($llx2>=$urx || $urx2<=$llx || $ury2<=$lly|| $lly2>=$ury)} { # match set found 1 set found_bbox $icc_bbox } } incr i puts "LUT COUNT: ($i $j) $found {$icv_bbox} {$found_bbox}" } timer "end while" }