java - 测试 Array 是否已排序或仅对其进行排序并从那里开始是否更有效?
问题描述
我编写了一种方法来找到我一无所知的数组中的中位数,除了它带有双打。它也在工作,但由于我不知道它可能有多大,我想知道我正在做的事情是否有效。如果数组未排序而不是直接排序,我应该检查它吗?或者如果我无论如何都要对它进行排序,那会是一个不必要的步骤吗?是我推荐的排序方式还是我错过了更好的方式?
//I calculate the median and return it.
public static double median(double[] vals) { //(un-)sorted Array
double median = 0;
sortedVals = Arrays.stream(vals).sorted().toArray(); //sorts low to high
int middleOfArray = (sortedVals.length) / 2 - 1;
int secondMiddleOfUnevenArray = (sortedVals.length) / 2;
if(sortedVals.length % 2 == 1) { //uneven values in Array
median = sortedVals[middleOfArray] + 1;
} else if(sortedVals.length % 2 == 0) { //even values in Array
median = (sortedVals[middleOfArray] + sortedVals[secondMiddleOfUnevenArray]) / 2;
} else {
System.out.println("Method median: error");
}
return median;
}
解决方案
这似乎是一个基于意见的问题,但从技术上讲,检查输入数组是否已排序可能是有意义的——它具有线性 O(N) 复杂性,对于随机输入,只需检查几个元素。
public static boolean isSorted(double ... arr) {
if (arr == null) {
return false;
}
int currOrder = 0;
for (int i = 1; i < arr.length; i++) {
int nextOrder = Double.compare(arr[i], arr[i - 1]);
if (currOrder == 0) currOrder = nextOrder;
if (nextOrder != 0 && nextOrder != currOrder) {
// System.out.println("Non-sorted at index=" + i + ": " + Arrays.asList(arr[i - 2], arr[i - 1], arr[i])); // log message
return false;
}
}
return true;
}
接下来,最小长度为 2 的数组似乎存在中位数,因此需要对其计算进行固定:
public static Double median(double ... vals) { //(un-)sorted Array
if (vals == null || vals.length < 2) {
return null; // or throw some exception
}
if (!isSorted(vals)) { // O(N)
Arrays.sort(vals); // O(N log N)
}
int mid = vals.length / 2;
if(vals.length % 2 == 1) { //uneven values in Array
return vals[mid];
}
// avoid addition overflow
return vals[mid - 1] / 2 + vals[mid] / 2;
}
测试:
System.out.println("between max even: " + median(Double.MAX_VALUE, Double.MAX_VALUE));
System.out.println("between max odd: " + median(Double.MAX_VALUE, Double.MIN_VALUE, Double.MAX_VALUE) + "; MAX=" + Double.MAX_VALUE);
System.out.println("odd : " + median(1, 400, 50, 50, 100000));
System.out.println("even: " + median(1, 3, 50, 100000));
System.out.println("even: " + median(-1, -2, -50, 100000));
输出(启用日志):
between max even: 1.7976931348623157E308
Non-sorted at index=2: [1.7976931348623157E308, 4.9E-324, 1.7976931348623157E308]
between max odd: 1.7976931348623157E308; MAX=1.7976931348623157E308
Non-sorted at index=2: [1.0, 400.0, 50.0]
odd : 50.0
even: 26.5
Non-sorted at index=3: [-2.0, -50.0, 100000.0]
even: -1.5
推荐阅读
- javascript - 使用 async/await 进行顺序(阻塞调用)返回过早
- javascript - FullCalendar - slot duration not working below 1:30 minutes
- command-line-interface - 如何通过命令行解析 LBRY URL?
- python - Bokeh - 如何在两个不同的选项卡中拥有相同的小部件(或复制小部件)?
- tfs - 从 VSTS 获取工作项
- azure - Windows Azure VM 远程桌面连接问题,即使来自家庭连接
- c - 我的程序是否泄漏内存?
- php - Laravel Excel Img src 无法从存储中工作
- scala - Spark Dataframe:计算组之间的差异
- mysql - 存储过程 WHERE 动态检查参数 NAME 是否为空或有值