某日事不多,點開sentinel-core代碼學習,想看看qps、rt等是怎么統計的。
點開StatisticSlot類,發現里面是用DefaultNode增加qps,然后嘗試點開
DefaultNode->StatisticNode->ArrayMetric->MetricsLeapArray->LeapArray...
暈...怎么這么多類- -||| 中間還有MetricBucket、LongAdder...
其中LeapArray類有個屬性AtomicReferenceArray<WindowWrap<T>> array,表示這個jdk類也是第一次見orz
看注釋寫道Using sliding window algorithm,使用了滑動窗口算法。可是這代碼太深奧T_T,表示打擾了,還是洗洗睡了Zzz....
--------------------------------------------------------------------------------------------------------------------------------------------
言歸正傳,雖然sentinel中的代碼還看不懂,通過滑動窗口幾個字,百度了解一下:)
找到一個經典的問題:
(一)給定一組大小為n的整數數組,計算長度為k的子數組和的最大值。
比如
數組為:1,2,3,4
最大值為:3+4=7
數組為:-1,4,7,-3,8,5,-2,6
最大值為:7-3+8=12
想到最簡單思路,那就遍歷所有子數組唄,求和然后比較。
int index = 0;// 記錄最大子數組第1個元素的索引,目前是0 int maxSum = 0;// 記錄最大子數組和,目前是從左開始第1個子數組 for (int i = 0; i < k; i++) { maxSum += array[i]; } for (int i = 1; i <= array.length - k; i++) {// 遍歷所有子數組,求和並比較 int curSum = 0; for (int j=0; j < k; j++) {// 計算當前子數組和 curSum += array[i + j]; } if (curSum > maxSum) {// 如果大於最大和,則記錄 maxSum = curSum; index = i; } }
運用滑動窗口思路,遍歷時不嵌套循環計算所有值;外層遍歷相當於窗口向右滑動,每次減去失效值加上最新值,即為當前窗口的和,然后再比較。
int index = 0;// 記錄最大子數組第1個元素的索引,目前是0 int maxSum = 0;// 記錄最大子數組和,目前是從左開始第1個子數組 for (int i = 0; i < k; i++) { maxSum += array[i]; } int curWindowSum = maxSum; for (int i = 1; i <= array.length - k; i++) {// 從下個元素開始,即窗口向右滑動 curWindowSum = curWindowSum - array[i - 1] + array[k + i - 1];// 減去失效值,加上最新值 if (curWindowSum > maxSum) {// 如果大於最大和,則記錄 maxSum = curWindowSum; index = i; } }
可以看到代碼差不多,只不過在計算求和時,采取了滑動窗口技術(思路),通過一減一加求和,消除了內部的循環。
注:這里為了突出語義,將變量名curSum改為curWindowSum
完整代碼如下:
package com.cdfive.learn2018.algorithm; /** * 求數組array長度為k的子數組的最大和 * * 算法1-cal * 遍歷所有子數組,求和並比較 * 嵌套循環 O(n*k) * * 算法2-calByLeapWinow * 窗口向右滑動,減去失效值加上最新值 * 單層循環 O(n) * * input: array=[1,2,3,4] k=2 * output: 7 // 3+4 * * input: array=[-1,4,7,-3,8,5,-2,6] k=3 * output: 12 // 7-3+8 * * @author cdfive * @date 2018-12-02 */ public class SimpleLeapWindow1 { public static void main(String[] args) { cal(new int[]{1, 2, 3, 4}, 2); cal(new int[]{-1,4,7,-3,8,5,-2,6}, 3); System.out.println("-------------"); calByLeapWinow(new int[]{1, 2, 3, 4}, 2); calByLeapWinow(new int[]{-1,4,7,-3,8,5,-2,6}, 3); } /** * 遍歷所有子數組,求和並比較 * 嵌套循環 O(n*k) */ public static void cal(int[] array, int k) { if (array.length == 0 || k <= 0 || k > array.length) {// 非法參數不處理 return; } int index = 0;// 記錄最大子數組第1個元素的索引,目前是0 int maxSum = 0;// 記錄最大子數組和,目前是從左開始第1個子數組 for (int i = 0; i < k; i++) { maxSum += array[i]; } for (int i = 1; i <= array.length - k; i++) {// 遍歷所有子數組,求和並比較 int curSum = 0; for (int j=0; j < k; j++) {// 計算當前子數組和 curSum += array[i + j]; } if (curSum > maxSum) {// 如果大於最大和,則記錄 maxSum = curSum; index = i; } } /**打印結果*/ System.out.print(maxSum + " // ");// 打印最大和 System.out.print(array[index]);// 先打印第1個值 for (int i = 1; i < k; i++) { int value = array[i + index]; System.out.print(value >= 0 ? ("+" + value) : value);// 非負數前面打印+號 } System.out.println(); } /** * 窗口向右滑動,通過減失效值加最新值求和並比較 * 單層循環 O(n) */ public static void calByLeapWinow(int[] array, int k) { if (array.length == 0 || k <= 0 || k > array.length) {// 非法參數不處理 return; } int index = 0;// 記錄最大子數組第1個元素的索引,目前是0 int maxSum = 0;// 記錄最大子數組和,目前是從左開始第1個子數組 for (int i = 0; i < k; i++) { maxSum += array[i]; } int curWindowSum = maxSum; for (int i = 1; i <= array.length - k; i++) {// 從下個元素開始,即窗口向右滑動 curWindowSum = curWindowSum - array[i - 1] + array[k + i - 1];// 減去失效值,加上最新值 if (curWindowSum > maxSum) {// 如果大於最大和,則記錄 maxSum = curWindowSum; index = i; } } /**打印結果*/ System.out.print(maxSum + " // ");// 打印最大和 System.out.print(array[index]);// 先打印第1個值 for (int i = 1; i < k; i++) { int value = array[i + index]; System.out.print(value >= 0 ? ("+" + value) : value);// 非負數前面打印+號 } System.out.println(); } }
--------------------------------------------------------------------------------------------------------------------------------------------
參考:
滑動窗口法詳解 https://blog.csdn.net/sty945/article/details/79846516
Window Sliding Technique https://www.geeksforgeeks.org/window-sliding-technique/
[LeetCode]Sliding Window Algorithm相關題目總結 https://blog.csdn.net/Ellie_/article/details/76781877
