我一直认为迭代搜索是在未排序列表中查找最大值的首选方法。
这个想法是随机出现的,但简而言之:我相信我可以在 O(logn) 时间内完成任务,其中 n 是输入数组的大小。
该方法搭载了归并排序:分而治之。
第 1 步:将 findMax() 任务分为两个子任务findMax(leftHalf)
和findMax(rightHalf)
. 这种划分要及时完成O(logn)
。
第 2 步:合并两个最大的候选项。这一步中的每一层都应该花费恒定的时间这是大错特错了。每次比较都是在恒定时间内完成的,但是要进行O(1)
,并且根据上一步,O(logn)
这样的层。所以它也应该及时完成O(1) * O(logn) = O(logn)
(原谅符号的滥用)。2^j/2
这样的比较(第 j 级的 2^j 对候选对象)。
因此,整个任务应该及时完成O(logn)
。O(n)
时间。
但是,当我尝试计时时,我得到的结果清楚地反映了线性O(n)
运行时间。
大小 = 100000000 最大值 = 0 时间 = 556
大小 = 200000000 最大值 = 0 时间 = 1087
大小 = 300000000 最大值 = 0 时间 = 1648
大小 = 400000000 最大值 = 0 时间 = 1990
大小 = 500000000 最大值 = 0 时间 = 2190
大小 = 600000000 最大值 = 0 时间 = 2788
大小 = 700000000 最大值 = 0 时间 = 3586
怎么来的?
这是代码(我未初始化数组以节省预处理时间,据我测试,该方法准确识别未排序数组中的最大值):
public static short findMax(short[] list) {
return findMax(list, 0, list.length);
}
public static short findMax(short[] list, int start, int end) {
if(end - start == 1) {
return list[start];
}
else {
short leftMax = findMax(list, start, start+(end-start)/2);
short rightMax = findMax(list, start+(end-start)/2, end);
return (leftMax <= rightMax) ? (rightMax) : (leftMax);
}
}
public static void main(String[] args) {
for(int j=1; j < 10; j++) {
int size = j*100000000; // 100mil to 900mil
short[] x = new short[size];
long start = System.currentTimeMillis();
int max = findMax(x);
long end = System.currentTimeMillis();
System.out.println("size = " + size + "\t\t\tmax = " + max + "\t\t\t time = " + (end - start));
System.out.println();
}
}