package ch.fhnw.claudemartin.algd1.maxteilsumme; import java.util.Arrays; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; public class MaxT { static int naive(byte[] a) { int sum = 0; int x; loop1: for (int left = 0; left < a.length; left++) { while (a[left] <= 0) continue loop1; loop2: for (int right = a.length - 1; right >= left; right--) { while (a[right] <= 0) continue loop2; x = 0; for (int i = left; i <= right; i++) { x += a[i]; } if (x > sum) sum = x; } } return sum; } public static void main(String[] args) { test(new byte[] { 42 });// 42 test(new byte[] { -1, 0, 1 });// 1 test(new byte[] { 1, 0, 1 });// 2 test(new byte[] { 1, 1, 1 });// 3 test(new byte[] { -1 });// 0 test(new byte[] { 10, 21, -13, 7, 9, -4, -9, 21, -6, 13, 17, 12, 1, -7, -6, 9 });// 79 test(new byte[] { 31, -41, 59, 26, -53, 58, 97, -93, -23, 84 });// 187 for (int i = 0; i < 10; i++) { test(1000 + i); } for (int i = 0; i < 10; i++) { test((int) Math.pow(10, i)); } } static int seed = 0; private static void test(int n) { Random random = new Random(seed++); final byte[] a = new byte[n]; for (int i = 0; i < a.length; i++) { a[i] = (byte) ((random.nextDouble() - 0.5) * Byte.MAX_VALUE); } test(a); } private static void test(final byte[] a) { // int[] a = { 2, -1, 3 }; // System.out.println(Arrays.toString(a)); long start = System.currentTimeMillis(); final int maxT = maxTeilsumme(a); long end = System.currentTimeMillis(); System.out.println("length: " + a.length); System.out.println("result: " + maxT); System.out.println("time (ms): " + (end - start)); if (a.length <= 5000) { final long s = System.currentTimeMillis(); int naive = naive(a); if (maxT != naive) { System.err.println("Wrong result!!!"); System.err.println("Naive result: " + naive); System.err.println("Array: " + Arrays.toString(a)); } System.out.println("time of naive impl. (ms): " + (System.currentTimeMillis() - s)); } System.out.println("----------------"); } static int maxTeilsumme(final byte[] a) { if (a.length == 0) return 0; final int left = 0; final int right = a.length - 1; // erst bei sehr grossen Arrays lohnt sich Multithreading: if (a.length < 1000000) return maxTeilsumme(a, left, right); // else: // System.out.println(left+", "+right); final int m = left + ((right - left) >> 1); assert m > left && m < right; final AtomicInteger vLsum = new AtomicInteger(); Thread t1 = new Thread() { public void run() { vLsum.set(maxTeilsumme(a, left, m)); }; }; final AtomicInteger vRsum = new AtomicInteger(); Thread t2 = new Thread() { public void run() { vRsum.set(maxTeilsumme(a, m + 1, right)); }; }; final AtomicInteger asum = new AtomicInteger(); Thread t3 = new Thread() { public void run() { asum.set(sum(a, left, right)); }; }; t1.start(); t2.start(); t3.start(); try { t1.join(); t2.join(); t3.join(); } catch (InterruptedException e) { e.printStackTrace(); } return max(vLsum.get(), vRsum.get(), asum.get()); } static int maxTeilsumme(final byte[] a, final int left, final int right) { assert right >= left; // System.out.println(left+", "+right); switch (right - left) { case 0: return a[left] > 0 ? a[left] : 0; case 1: return max(0, a[left], a[right], a[left] + a[right]); case 2: final int lft = a[left]; final int mid = a[right - 1]; final int rgt = a[right]; return max(0, lft, mid, rgt, a[left] + mid, mid + a[right], a[left] + mid + a[right]); case 3: final int a1 = a[left];// right-3 final int a2 = a[left + 1];// right-2 final int a3 = a[right - 1];// left+2 final int a4 = a[right];// left+3 final int a12 = a1 + a2; final int a34 = a3 + a4; return max(0, a1, a2, a3, a4, a12, a2 + a3, a34, a12 + a3, a2 + a34, a12 + a34); default: int m = left + ((right - left) >> 1); assert m > left && m < right; int vLsum = maxTeilsumme(a, left, m); int vRsum = maxTeilsumme(a, m + 1, right); int asum = sum(a, left, right); return max(vLsum, vRsum, asum); } } static int sum(byte[] a, int left, int right) { int sum = 0; int rmax = 0; int m = left + ((right - left) >> 1); for (int i = m + 1; i <= right; i++) { sum += a[i]; if (sum > rmax) rmax = sum; } sum = 0; int lmax = 0; for (int i = m; i >= left; i--) { sum += a[i]; if (sum > lmax) lmax = sum; } return lmax + rmax; } static int max(int... vals) { assert vals.length > 0; int rv = Integer.MIN_VALUE; for (int i : vals) { if (i > rv) rv = i; } assert rv != Integer.MIN_VALUE; return rv; } }