Время работы алгоритма

252
25 ноября 2021, 01:50

возникла небольшая проблема. Написал программу, которая ищет 2 ближайшие точки 2-мя методами: декомпозиции и полным перебором. Из теории мне известно, что время работы метода грубой силы O(n^2), а метода декомпозиции О(nlogn). Но при реализации программы, сравнивая время, получается, что сколько бы точек я не брал, разница всегда +- в m раз. Можете ли подсказать в чем может быть дело? Что-то в программе?

import static java.lang.Math.sqrt;

import java.util.ArrayList;
 public class BruteFindClosestPoints {
int index1 = -1;
int index2 = -1;
double min;
double BruteFindClosestPoints(ArrayList<Point> arrayPoint) {
    min = Integer.MAX_VALUE;
    double d;
    for (int i = 0; i < arrayPoint.size() - 1; i++) {
        for (int j = i + 1; j < arrayPoint.size()&&j!=i; j++) {
            d = Math.pow((arrayPoint.get(j).X - arrayPoint.get(i).X), 2)
                    + (Math.pow((arrayPoint.get(j).Y - arrayPoint.get(i).Y), 2));
            if (d < min) {
                min = d;
                index1 = arrayPoint.get(i).getID();
                index2 = arrayPoint.get(j).getID();
            }
        }
    }
    min = sqrt(min);
    return min;
}
public int getIndex1() {
    return index1;
}
public int getIndex2() {
    return index2;
}
void show() {
    System.out.println("Ближайшие точки (BruteForce): " + (index1) + " и " + (index2) + " с расстоянием: " + min);
}

}

Дальше метод декомпозиции:

import static java.lang.Math.abs;
import static java.lang.Math.sqrt;
import java.util.ArrayList;
public class DecompositionFindClosestPoints {
int index1 = -1, index2 = -1;
int index3 = -1, index4 = -1;
double m = Integer.MAX_VALUE;
double DecompositionFindClosestPoints(ArrayList<Point> pointSortedX, ArrayList<Point> pointSortedY) {
    int lgth = pointSortedX.size();
    if (lgth <= 3) {
        BruteFindClosestPoints a = new BruteFindClosestPoints();
        double dist = a.BruteFindClosestPoints(pointSortedX);
        index1 = a.getIndex1();
        index2 = a.getIndex2();
        return dist;
    }
    int mid = lgth / 2;
    Point midPoint = new Point(pointSortedX.get(mid));
    ArrayList<Point> Pxl = new ArrayList<>(pointSortedX.subList(0, mid + 1));
    ArrayList<Point> Pxr = new ArrayList<>(pointSortedX.subList(mid + 1, lgth));
    ArrayList<Point> Pyl = new ArrayList<>();
    ArrayList<Point> Pyr = new ArrayList<>();
    for (int i = 0; i < lgth; i++) {
        if (pointSortedY.get(i).getX() <= midPoint.getX()) {
            Pyl.add(pointSortedY.get(i));
        } else {
            Pyr.add(pointSortedY.get(i));
        }
    }
    DecompositionFindClosestPoints dl_ = new DecompositionFindClosestPoints();
    DecompositionFindClosestPoints dr_ = new DecompositionFindClosestPoints();
    double dl = dl_.DecompositionFindClosestPoints(Pxl, Pyl);
    double dr = dr_.DecompositionFindClosestPoints(Pxr, Pyr);
    double d;
    if (dl < dr) {
        index1 = dl_.getIndex1();
        index2 = dl_.getIndex2();
        d = dl;
    } else {
        index1 = dr_.getIndex1();
        index2 = dr_.getIndex2();
        d = dr;
    }
    ArrayList<Point> strip = new ArrayList<>();
    for (int i = 0; i < pointSortedY.size(); i++) {
        if (abs(pointSortedY.get(i).getX() - midPoint.getX()) < min(d, m)) {
            strip.add(pointSortedY.get(i));
        }
    }
    double dist = stripClosest(strip, d, Pxl, Pxr);
    if (dist < d) {
        index1 = index3;
        index2 = index4;
        m = dist;
    } else {
        m = d;
    }
    return m;
}
double stripClosest(ArrayList<Point> a, double d, ArrayList<Point> Pxl, ArrayList<Point> Pxr) {
    double min = d;
    double dist;
    for (int i = 0; i < a.size() - 1; i++) {
        for (int j = i + 1; j < a.size(); j++) {
            if (a.get(j).getY() - a.get(i).getY() < min) {
                if (!(Pxl.contains(a.get(j)) && Pxl.contains(a.get(i)))
                        || !(Pxr.contains(a.get(i)) && Pxr.contains(a.get(j)))) {
                    dist = sqrt(Math.pow((a.get(j).X - a.get(i).X), 2)
                            + (Math.pow((a.get(j).Y - a.get(i).Y), 2)));
                    if (dist < min) {
                        min = dist;
                        index3 = a.get(i).getID();
                        index4 = a.get(j).getID();
                    }
                } else {
                }
            } else {
                j = a.size();
            }
        }
    }
    return min;
}
public int getIndex1() {
    return index1;
}
public int getIndex2() {
    return index2;
}
void show() {
    System.out.println("Ближайшие точки (Decomposition): " + (index1) + " и " + (index2) + " с расстоянием: " + m);
}
double min(double x, double y) {
    return (x < y) ? x : y;
}

}

Главный класс:

import java.awt.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Random;

public class FindPoint {
public static void main(String[] args) {
    long averageTimeDecomposition = 0;
    long averageTimeBrute = 0;
    for (int j = 0; j < 10; j++) {
        ArrayList<Point> point = new ArrayList<>();
        int min = 0;
        int max = 100;
        HashSet<Integer> ptX = new HashSet<>();
        for (int i = 0; i < 10; i++) {
            Random rnd = new Random();
            int rndX = min + rnd.nextInt(max - min + 1);
            int rndY = min + rnd.nextInt(max - min + 1);
            if (!ptX.contains(rndX)) {
                ptX.add(rndX);
                point.add(new Point(rndX, rndY, point.size()));
                System.out.println(point.size() + ": " + " X: " + rndX + " Y: " + rndY);
            } else {
                i--;
            }
        }
        double check1;
        double check2;
        long startTime = System.nanoTime();
        BruteFindClosestPoints a = new BruteFindClosestPoints();
        check1 = a.BruteFindClosestPoints(point);
        a.show();
        averageTimeBrute += System.nanoTime() - startTime;
        Collections.sort(point, Point.COMPARE_BY_X);
        ArrayList pointX = new ArrayList<>(point);
        Collections.sort(point, Point.COMPARE_BY_Y);
        ArrayList pointY = new ArrayList<>(point);
        startTime = System.nanoTime();
        DecompositionFindClosestPoints b = new DecompositionFindClosestPoints();
        check2 = b.DecompositionFindClosestPoints(pointX, pointY);
        averageTimeDecomposition += System.nanoTime() - startTime;
        b.show();
        System.out.println("---------------------------------------");
    }
    System.out.println("Среднее время грубый: " + (averageTimeBrute / 1000));
    System.out.println("Среднее время декомпозиции: " + (averageTimeDecomposition / 1000));
}

} И последний класс:

import java.util.Comparator;
import java.util.Random;
public class Point {
int X;
int Y;
int id;
public Point(int X, int Y, int id) {
    this.X = X;
    this.Y = Y;
    this.id = id;
}
public Point(Point a) {
    this.X = a.getX();
    this.Y = a.getY();
    this.id = a.getID();
}
public Point(int id) {
    Random random = new Random();
    this.X = random.nextInt();
    this.Y = random.nextInt();
    this.id = id;
}
public int getX() {
    return X;
}
public void setX(int X) {
    this.X = X;
}
public int getY() {
    return Y;
}
public void setY(int Y) {
    this.Y = Y;
}
public int getID() {
    return id;
}
public void setID(int id) {
    this.id = id;
}
public static final Comparator<Point> COMPARE_BY_X = new Comparator<Point>() {
    @Override
    public int compare(Point a, Point b) {
        return a.getX() - b.getX();
    }
};
public static final Comparator<Point> COMPARE_BY_Y = new Comparator<Point>() {
    @Override
    public int compare(Point a, Point b) {
        return a.getY() - b.getY();
    }
};
@Override
public String toString() {
    return "Point{" + "X=" + X + ", Y=" + Y + ", id=" + id + '}';
}

}

Answer 1

Код не смотрел, но сразу можно отметить, что сложность алгоритма не стоит ассоциировать со временем выполнения. Метод декомпозиции даже визуально выглядит сложнее.

Самое главное, зачем пишу. В Java не так просто замерить время выполнения. За кадром работает операционка с другими процессами, Garbage Collector, кроме того, в какой-то момент времени горячие участки кода компилируются, а часть кода, которая, как кажется JVM бесполезная, попросту может не выполняться.

Вот небольшое обсуждение, где всё это рассматривается немного подробнее: https://javatalks.ru/topics/26726

Тут пример, как можно замерить точнее: https://habr.com/ru/post/349914/

Тонкостей на самом деле много, с ходу не могу найти ссылку на материал, где все нюансы описаны в полной мере.

READ ALSO
Spring cloud, auth-service

Spring cloud, auth-service

Создаю приложение на микросервисной архитектуре с использованием Spring Boot, Spring CloudКак пример я смотрю вот этот репозиторий

196
Java Timer Animation

Java Timer Animation

Необходимо по таймеру увеличивать и уменьшать сферу например за 5 секунд увеличить и за 5 секунд уменьшить, этот код работает, ну я не знаю...

181
защита desktop-приложения на java

защита desktop-приложения на java

Есть старый проект(xul, tomcat 5, jdk 15, hibernate, firebird и т

99