Наилучшая производительность алгоритма в уравнении многих значений

1

Я сейчас разрабатываю приложение для Android. и у меня возникла проблема с одним важным методом в моем приложении, потому что я не могу сделать лучший алгоритм, чтобы приравнивать многие входы ко многим данным.

Здесь сценарий: вход метода - это координаты из метода переопределения onTouchEvent(), поэтому вход будет таким большим, когда коснется экран и будет перемещен палец. я должен приравнять, что так много-координаты до 24 значений в массиве. значения в массиве также являются координатами. Поэтому, когда вход имеет то же значение, что и значения в массивах, он забивает точку.

здесь код, который я использовал:

public void checkCoordinate(float x, float y){
    int sensitivity = 30; 
    for(int z = 0; z < 24; z++){
        if(x > (cxy[z][0]-sensivity) && x < (cxy[z][0]+sensivity) && y > (cxy[z][1]-sensivity) && y < (cxy[z][1]+sensivity)){
            points += 1; 
            Log.i("CheckCoordinate", "Total Points = "+points); 
    }
}

У меня есть два способа приравнять его. один, используя вышеприведенный алгоритм или, используя 24, если проверять каждый вход. но я не думаю, что в этом случае 2 способа хороши. поэтому мне нужна ваша помощь, если у вас был тот же случай, что и у меня, и вы решили, что у вас есть лучшее или лучшее решение, пожалуйста, скажите мне.

заранее спасибо. извините, если мой английский плохой.

  • 0
    Вам нужно посмотреть на это: stackoverflow.com/questions/245509/…
  • 0
    Итак, в конечном итоге вы пытаетесь увидеть, находится ли ваш палец в пределах 1 из 24 областей, каждая область определяется одной точкой, и значение чувствительности? Кроме того, в чем здесь проблема, это медленнее, чем вы хотели бы, это не работает, и т.д ... ???
Показать ещё 6 комментариев
Теги:
algorithm

2 ответа

1
Лучший ответ

С учетом сказанного ваша общая идея верна. Вопрос в том, может ли он теперь быть оптимизирован каким-то образом?

Есть много методов, которые мы можем использовать здесь. Трюк все в том, как вы упорядочиваете свои данные. В вашем текущем случае вы делаете центр с переменной чувствительности, являющейся вашим диапазоном. Можно представить, что первая оптимизация вместо использования чувствительности, которая перемещается слева направо вверх и вниз от центральной точки, вы можете вместо этого использовать верхнюю левую точку с пролетом, который перемещается только справа и слева от верхней левой точки. Тогда ваш оператор if:

if(x > cxy[z][0] && x < (cxy[z][0]+sensivity) && y > cxy[z][1] && y < (cxy[z][1]+sensivity))

Итак, что это для вас делает: эта оптимизация позволяет вам сохранить общий объем данных, но избавиться от 2 математических операций за проверку. Учитывая, что ваши входные параметры являются плавающими точками, это может сэкономить немало времени.

Если вы выполняете все операции на основе пикселей, это приводит меня к следующей оптимизации. Выполняйте ВСЕ-вычисления с использованием целых чисел вместо плавающей запятой, это также значительно ускорит ваше общее время алгоритма.

дальнейшая оптимизация теперь может быть, если вы захотите потратить больше ОЗУ для повышения производительности, вы можете вместо 1 точки на регион, у вас может быть верхняя левая и нижняя правая точки для каждого региона. Это заставит ваш оператор if выглядеть примерно так:

if(x > tlxy[z][0] && x < brxy[z][0] && y > tlxy[z][1] && y < brxy[z][1])

where tlxy is the array of top-left points, brxy is the array of bottom-right points
and z is still the "region" you are checking against

Как это помогает: как вы можете видеть в приведенном выше примере if, это теперь абсолютно не имеет явных математических операций. Чтобы поддержать этот алгоритм, вы должны быть готовы потратить в 2 раза больше памяти, чем исходный массив cxy.

Теперь в вашем цикле вы проходите ВСЕ 24 региона. Если вы ЗНАЕТЕ В ОТНОШЕНИИ ОТНОШЕНИЙ, что ни одна из ваших областей не перекрывается, тогда точка может действительно только упасть в 1 регионе за раз. Вы можете сэкономить некоторое время на большинстве входных точек xy, вырвавшись из цикла for в точке, где вы также увеличиваете точки. Это выглядит следующим образом:

public void checkCoordinate(float x, float y){
    for(int z = 0; z < 24; z++){
        if(x > tlxy[z][0] && x < brxy[z][0] && y > tlxy[z][1] && y < brxy[z][1]){
            points += 1; 
            break;
        }
    }
}

Вышесказанное будет ТОЛЬКО РАБОТАТЬ IFF, который вы знаете наверняка, что нет перекрывающихся областей (даже не краев.

По окончательной оптимизации, я вижу, может иметь потенциал. В зависимости от того, как выглядят ваши регионы, вы можете предварительно разделить все регионы на квадранты. Таким образом, вы можете проверить точку x на левой или правой стороне экрана, а затем проверить, что y-точка находится в верхней или нижней части. Если распределение ваших регионов довольно ровное, это может иметь потенциал сократить время тестирования на 4, так как вам не нужно будет тестировать только регионы в квадранте (если это статистическое распределение - это то, что я сказал). В худшем случае все регионы лежат в одном квадранте, и все точки, которые вы тестируете, находятся в этом квадранте, и в этом случае проблема с точки зрения сложности не хуже, чем раньше. Он просто добавляет тест установки на ваш вход x и y.

Надеюсь, это даст вам достаточно информации, по крайней мере, на вашем пути!

  • 0
    Ух ты, я никогда не думал об использовании break in if, а вычисление с использованием float тяжелее целого числа. Я пытался, и он отлично работает в AVD, и я верю, что это будет более плавным в устройстве. Большое спасибо!
  • 0
    Нет проблем, я надеюсь, что ДЕЙСТВИТЕЛЬНО хорошо работает на вашем устройстве, продолжайте веселиться :-)
0

Для 24 значений это может быть чрезмерным, но вы также можете рассмотреть использование хэш-таблицы простого массива (с открытым конфликтом при разрешении адресации):

  1. Для простоты предположим, что вы используете значение y для получения положения перехода (если области хорошо разделены по вертикали, это должно уменьшить количество проверок). Предполагая, что разрешение экрана 600x800, вы можете разделить y на 60, чтобы получить ~ 13 слотов. Если вы используете 8-битную таблицу, round(800/60)=13 ~ 18 элементам на каждый слот (round(800/60)=13, round(255/13)=18).

  2. Чтобы ускорить вычисления, вы должны держать все вокруг и просто, так что вы можете получить номер слота, используя:

    int yi = (int)y;
    
    // this is your "hash function". depending on your actual data,
    // you might want to modify it to get a lesser chance of collisions
    byte slot = (byte)((yi / 60) * 18);
    
  3. Теперь, когда у вас есть индекс слота, просто перейдите в хэш-таблицу и проверьте, нет ли еще элементов для проверки:

    rectangle r;
    int yi = (int)y;
    for (byte slot=(byte)(yi / 26); slot < 256; slot++)
    {
        r = hashtable[slot];
    
        // is this an empty slot?
        if (r.brxy == 0)
           break;
    
        // perform exact check
        if (r.left < x && x < r.right && 
            r.top < y && y < r.bottom)
           break;
    }
    
  4. Таблицу хэшей необходимо создать во время init аналогичным образом: для каждого из ваших 24 регионов вычислите свой индекс хэша (слота). Если позиция в хеш-таблице занята, просто увеличивайте ее на 1, пока не найдете пустое место. ПРИМЕЧАНИЕ. Вам нужно будет добавить каждый регион во все перекрывающиеся слоты. Самый простой способ - добавить его в слоты s, s-1 и s+1.

В настоящее время ваш цикл выполняет 12 поисковых запросов, в то время как хэш-подход выполняет одиночный расчет хэша и должен требовать в среднем только два или три поиска (хеш-таблицы, как говорят, имеют сложность O(1) в среднем, предполагая хорошую хэш-функцию).

пример

Ваша hashtable должна идеально выглядеть примерно так:

hashtable[0]: rectangle(0, 0, 60, 60);
hashtable[1]: rectangle(20, 20, 80, 80);
hashtable[2]: (empty)
hashtable[3]: (empty)
...
// next slot starts at [18]
hashtable[18]: rectangle(20, 20, 80, 80); // this region is in slots 0 and 1
hashtable[19]: rectangle(30, 70, 90, 130);
hashtable[20]: rectangle(400, 70, 460, 130);
hashtable[21]: (empty)
...

Итак, если ваша точка касания (430, 100), расчет будет продолжаться следующим образом:

a) slot = (byte)((100/60) * 18) = 18;
b) check hashtable[18], overlapping? no
c) check hashtable[19], overlapping? no
c) check hashtable[20], overlapping? yes, found after 3 checks

Производительность зависит только от выбранной хэш-функции:

Если у вас много элементов с одинаковыми координатами x, вы можете получить много столкновений в некоторых слотах: вот почему важно выбрать хорошую хеш-функцию. Если регионы фиксированы, вы даже можете создать идеальный хеш.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню