跳转至

在大数组中查找第N个有序元素

原文链接: https://www.nv5geospatialsoftware.com/Learn/Blogs/Blog-Details/finding-the-nth-ordered-element-in-a-large-array

13793 为本文评分:

暂无评分

在大数组中查找第N个有序元素

匿名作者 2014年7月17日,星期四

处理大型数组时,一个常见任务是查找有序数组中的第N个数组值。这对于查找第N个最小或最大像素值,以及对浮点数据样本进行统计分析(例如查找95%百分位数或类似操作)非常有用。在IDL中查找有序序列中第N个值的最简短代码实际上只需2行。以下是实现此功能的简短函数:

;+

; 返回有序序列中的第N个数字

;-

function ordinal_1, array, N

compile_opt idl2,logical_predicate

s = sort(array)

return, array[s[N]]

end

然而,由于排序是一项计算密集型操作,该函数运行速度相当慢,特别是当数组变大时。我进行了以下时间测试。

IDL> a = total(read_image(filepath('ohare.jpg',subdir=['examples','data'])),1)

IDL> tic & x = ordinal_1(a, 123456) & toc & print, x

% Time elapsed: 3.7200000 seconds.

150.000

在我的测试中,查找第123456个最小的数组元素耗时3.72秒。IDL中的MEDIAN函数通过不完全排序返回有序序列的中心元素。它比排序快得多,因为它不需要跟踪所有元素及其有序位置,只关心有序数组中第N/2个元素。在以下示例中,通过反复调用MEDIAN函数并每次迭代将数组大小减半,来查找有序序列中的第N个元素。这段代码比上面的代码长得多,但最终运行速度更快:

;+

; 返回有序序列中的第N个数字。

;

; 使用重复中值法。

;-

function ordinal_2, array, N

compile_opt idl2,logical_predicate

na = n_elements(array)

type =size(array, /type)

target_index = N

tmp = arg_present(array) ? array : temporary(array)

ntmp = na

while ntmp ne target_index do begin

ntmp = n_elements(tmp)

val = fix(median(tmp), type=type)

if target_index gt ntmp/2 then begin

tmp = tmp[where(tmp gt val, count)]

target_index -= ntmp-count

endif else if target_index lt ntmp+1/2 then begin

tmp = tmp[where(tmp lt val, count)]

endif else break

if target_index lt 0 then break

if target_index ge count then break

if target_index eq 0 then begin

val = min(tmp)

break

endif

if target_index eq count-1 then begin

val = max(tmp)

break

endif

endwhile

return, val

end

对这段代码进行与简短代码相同的时间测试:

IDL> tic & x = ordinal_2(a, 123456) & toc & print, x

% Time elapsed: 0.57999992 seconds.

150.000

由此可见,时间节省非常显著,从3.72秒减少到0.58秒。随着数组增大,节省的时间可能更加显著。此函数适用于浮点型和整型数组等数值数据类型。

夜与日的差异 图像服务的兴起