Fortran:有两个大的整数数组,目的是找出它们是否有任何共同点,如何?
您可以认为两者的大小相同(情况1)或大小不同(情况2)。它们也可能有许多重复的常用数字,因此应该对其进行处理以避免不必要的搜索或操作符。
最简单的方法是进行不合适的暴力搜索。我们正在考虑类似于 Python 的SET
操作,如下所示:
a = set([integers])
b = set([integers])
incommon = len(a.intersection(b)) > 0 #True if so, otherwise False
例如:
a = [1,2,3,4,5]
b = [0,6,7,8,9]
sa = set(a)
sb = set(b)
incommon = len(sa.intersection(sb)) > 0
>>> incommon: False
b = [0,6,7,8,1]
incommon = len(sa.intersection(sb)) > 0
>>> incommon: True
如何在Fortran中实现这一点?请注意,数组大小(> 10000)并且操作会重复数百万次!
更新 [关于问题的评论]我们绝对尝试了很多我们知道的方法。例如,如BFS方法所述。它有效但效率不高有两个原因:1)需要大量迭代的方法的性质,2)我们可以实现的代码。接受的答案(由yamajun提供)对我们来说非常有益,而不仅仅是问题本身。 Quick-Sort,Shrink和Isin的实现非常简单,并且非常好地实现了。我们赞赏这种迅速和完美的解决方案。
答案 0 :(得分:9)
也许这会奏效。
从此处添加
主要思想是使用内在函数ANY()。
现在我们尝试删除数组中的重复数字。
首先我们对数组进行排序。快速排序可以像Haskell一样简洁地编写。 (参考:Arjen Markus,ACM Fortran Forum 27(2008)2-5。) 但由于递归消耗堆栈,Shell-sort可能是更好的选择,不需要额外的内存。在教科书中经常说明Shell-sort在O(N ^ 3 / 2~5 / 4)中工作,但使用特殊的间隙函数它的工作速度要快得多。wikipedia
接下来,我们通过使用zip对的概念比较连续的元素来删除重复的数字。 [x(2)/ = x(1),...,x(n)/ = x(n-1)]我们需要添加额外的一个元素来匹配数组大小。内部函数PACK()用作过滤器。
到这里
program SetAny implicit none integer, allocatable :: ia(:), ib(:) ! fortran2008 ! allocate(ia, source = [1,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5]) ! allocate(ib, source = [0,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9]) allocate(ia(size([1,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5]))) allocate(ib(size([0,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9]))) ia = [1,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5] ib = [0,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9] print *, isin( shrnk( ia ), shrnk( ib ) ) stop contains logical pure function isin(ia, ib) integer, intent(in) :: ia(:), ib(:) integer :: i isin = .true. do i = 1, size(ib) if ( any(ia == ib(i)) ) return end do isin = .false. return end function isin pure function shrnk(ia) result(res) integer, intent(in) :: ia(:) integer, allocatable :: res(:) ! f2003 integer :: iwk(size(ia)) iwk = qsort(ia) res = pack(iwk, [.true., iwk(2:) /= iwk(1:)]) ! f2003 return end function shrnk pure recursive function qsort(ia) result(res) integer, intent(in) :: ia(:) integer :: res(size(ia)) if (size(ia) .lt. 2) then res = ia else res = [ qsort( pack(ia(2:), ia(2:) < ia(1)) ), ia(1), qsort( pack(ia(2:), ia(2:) >= ia(1)) ) ] end if return end function qsort end program SetAny
外壳排序
pure function ssort(ix) ! Shell Sort integer, intent(in) :: ix(:) integer, allocatable :: ssort(:) integer :: i, j, k, kmax, igap, itmp ssort = ix kmax = 0 do ! Tokuda's gap sequence ; h_k=Ceiling( (9(9/4)^k-4)/5 ), h_k < 4N/9 ; O(N)~NlogN if ( ceiling( (9.0 * (9.0 / 4.0)**(kmax + 1) - 4.0) / 5.0 ) > size(ix) * 4.0 / 9.0 ) exit kmax = kmax + 1 end do do k = kmax, 0, -1 igap = ceiling( (9.0 * (9.0 / 4.0)**k - 4.0) / 5.0 ) do i = igap, size(ix) do j = i - igap, 1, -igap if ( ssort(j) <= ssort(j + igap) ) exit itmp = ssort(j) ssort(j) = ssort(j + igap) ssort(j + igap) = itmp end do end do end do return end function ssort