• Как определить масштаб карты, если я знаю сколько метров у меня в 1 см?

    @odissey_nemo
    Писать на карте масштаб, не кратный стандартному (1:1000, 1:5 000, 1: 10 000, !:25 000, 1:50 000, 1:100 000, 1:250 000, 1:500 000, 1:1 000 000 и т.д.), не есть комильфо для глаза специалиста.
    Даже если требования стандартов к карте не предъявляются и карта является временной или рабочей, не для распространения, всё равно масштаб стараются сделать таким, чтобы хотя бы несколько последних цифр в нём были нулями. Скажем, 1:66 000 и т.д.
    На компьютерных "картах" лучше просто рисовать отрезок (внизу справа обычно) на экране и надписывать над ним число км на местности, помещающиеся в этом отрезке.
  • Как сделать круглое изображение?

    @odissey_nemo
    dimasik100200, я имел в виду, что растры хранятся только в виде прямоугольных матриц пикселов. А круглыми при просмотре их делают прозрачные пикселы в углах этих самых матриц)
  • Как сделать круглое изображение?

    @odissey_nemo
    Наверное, стоит написать "как сделать его выглядящим круглым". Круглых изображений не бывает в виртуальном мире, только в физическом :o(. А товарищи всё сказали правильно: нужна прозрачная маска в растре, которая сформирует круглый образ из прямоугольного растра. Давно не работал с изображениями, поэтому сказать ничего конкретного не смогу.
  • Какую сортировку применять?

    @odissey_nemo
    longclaps: Обострённая чувствительность - преходяща. Но только со временем. Ну какая зависть, уважаемый longclaps? Я подсознательно восхищён тем, как Вы быстро решили стандартными средствами не тривиальную (по кр. мере для меня) задачу. Если всё было сделано Вами вручную, с нуля - готов публично признаться в Вашем превосходстве в этой области.
  • Какую сортировку применять?

    @odissey_nemo
    artshelom: Абсолютно нормальное решение. Отвечающее задаче. Что и требовалось. Честно говоря, на скорость его не тестировал. Если интересно, протестирую. Но думаю, это лучше сделает автор, как лицо заинтересованное.

    Некоторая дискуссия тут возникла лишь по поводу нового и старого подходов. Двоичный поиск использовался в древние времена (я оттуда), когда в обиход ещё не вошли хэш-таблицы и прочие прелести современных стандартных библиотек.

    Фишка же современных (ПМСМ) собеседований в том, что сегодня на них ищут людей, знающих конкретные технологии, а не тех, которые способны реально мыслить в новых, неизвестных условиях. Что-то типа роботов, настроенных на конкретные операции. Не делаешь эту, новейшую операцию? Ты плохой робот, нам тебя не надо. От тебя нет немедленной отдачи, что есть наша основная цель.

    В целом это объективно оправдано в условиях перехода на индус-кодирование. Люди теперь - винтики, которых легко вывинтить и выбросить. И ими в таких условиях много легче командовать и эксплуатировать. И они не скрипят при быстром ввинчивании-вывинчивании :o). Всё - ПМСМ. Успехов!
  • Какую сортировку применять?

    @odissey_nemo
    package test;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.nio.charset.Charset;
    import java.nio.file.Paths;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Comparator;
    
    /**
     * Created by nemo_odissey on 10.07.2017 12:45 for
     * <a href="https://toster.ru/q/440261?utm_source=email_notifications&utm_medium=email&utm_content=mention&utm_campaign=notifications#comment_1428657" >Какую сортировку применять?</a>.
     */
    public class JapanEditor
    {
        /**
         * Class to store vocabulary item and make it comparable only  lexicographically
         */
        public static class WordItem implements Comparable
        {
            public String word;
            public int count;
    
            public WordItem( String word, int count )
            {
                this.count = count;
                this.word = word.split( "/",0 )[0];
            }
    
            @Override
            public int compareTo( Object obj )
            {
                return this.word.compareTo( ((WordItem)obj).word );
            }
    
            public int compareByFrequency( Object obj )
            {
                return this.count - ((WordItem)obj).count;
            }
        }
    
        /**
         * Сортирует и извлекает из массива source начиная с индекса pos1 и до индекса pos2 (не включая его самого) максимальные элементы,
         * по размеру массива result или меньше.
         * @param maxLen максимальный размер массива с максимальными элементами
         * @param dstList {@link ArrayList} для размещения результатов работы. Если {@code null}, то  будет создан внутри. Очищается перед работой и заполняется результатами
         * @param source исходный массив
         * @param pos1 начальный индекс массива source
         * @param pos2 конечный инидекс в массиве source (не включается в сортировку)
         * @return {@link ArrayList} (не может быть {@code null})
         */
        public static final ArrayList<WordItem> partialSort( int maxLen, ArrayList<WordItem> dstList, WordItem[] source, int pos1, int pos2 )
        {
            if ( dstList == null )
                dstList = new ArrayList<WordItem>( 10 );
            else
                dstList.clear();
            dstList.add( source[ pos1++ ] );
            // Проверим все слова с префиксом на предмет их частоты и отберём до 10 самых часто встречающихся
            for( int i = pos1; i< pos2; i++ )
            {
                WordItem item = source[ i ];
                int placeFound = 0;
                int listPos;
                int cmp;
                // Найдём, надо ли вставлять и куда вставить
                for ( listPos = dstList.size() - 1; listPos >= 0; listPos-- )
                {
                    if ( ( cmp = item.compareByFrequency( dstList.get( listPos ) ) ) < 0 ) // нашли элемент из списка проверенных, который больше проверяемого
                        break; // дальше не идём, может сможем добавить в конец списка, если там ещё есть место
                    if (cmp == 0) // по частоте он равен
                        if ( item.compareTo( dstList.get( listPos ) ) > 0 ) // но элемент из списка проверенных оказался меньше лексически
                            break;
                }
                // пытаемся вставить в массив либо на место элемента, который меньше, либо в конец списка, если там ещё есть место
                if ( listPos == (dstList.size()-1) ) // младший элемент списка больше проверяемого элемента, попробуем просто сдобавить в конец
                {
                    if ( dstList.size() < maxLen ) // массив результата ещё не полон, добавляем в конец
                        dstList.add( item );
                    continue; // переходим к следующему элементу
                }
                // нашли, куда вставить
                if ( dstList.size() == maxLen )
                {
                    // массив результата уже полностью заполнен, сразу удаляем нижний,
                    // т.к. он выйдет за разрешённые пределы при вставке нового элемента
                    dstList.remove( maxLen - 1 );
                }
                // вставляем ниже большего элемента, или, если listPos == -1, вместо самого большого
                dstList.add( listPos + 1, item );
            }
            return dstList;
        }
    
        /**
         * Обработки ошибок НЕТ
         * @param args путь_к_файлу_с_данными, где хранится задание
         * @throws IOException
         */
        public static void main( String[] args ) throws IOException
        {
            long start = System.nanoTime();
            BufferedReader brd  = java.nio.file.Files.newBufferedReader( Paths.get( args[ 0 ] ), Charset.forName( "utf-8" ) );
            // читаем число слов
            int wordCnt = Integer.parseInt( brd.readLine() );
            WordItem[] wordArr = new WordItem[wordCnt];
            // Читаем все слова и их частоты
            for(int i = 0; i < wordCnt; i++)
            {
                String word = brd.readLine();
                String[] elems = word.split( " " );
                wordArr[ i ] = new WordItem( elems[0], Integer.parseInt( elems[1] )  );
    //            wordArr[ i ] = new WordItem( word.toLowerCase(), freq );
            }
    
            // сортируем массив словаря
            Arrays.sort( wordArr );
    
            // считываем и обрабатываем каждый префикс один за другим
            int prefCnt = Integer.parseInt( brd.readLine() );
            System.out.printf( "Счётчик слов %d, счётчик префиксов %d\n", wordCnt, prefCnt );
            System.out.printf( "Словарь считан и отсортирован за %,f млс.\n\n",  1e-9 * (System.nanoTime() - start) );
            int summaryWordCount = 0;
            WordItem prefixItem = new WordItem( "", 1 );
            ArrayList<WordItem> list = new ArrayList<>( 11 );
            for(int i = 0; i < prefCnt; i++)
            {
                String prefix = brd.readLine().trim();
                prefixItem.word = prefix;
                int pos1 = Arrays.binarySearch( wordArr, prefixItem ); // if positive, point to a word in vocabulary started from prefix or equal to it
                if ( pos1 < 0) // no precise prefix value found in vocabulary
                    pos1 = -(pos1 + 1); // pos1 to the first element starting from prefix
                if ( pos1 >= wordCnt) // префикс отсутствует в словаре
                    continue;
    
                System.out.printf( "     ~ %s\n", prefix );
    
                if ( wordArr[pos1].word.startsWith( prefix ) ) // Если префикс есть, ищем последнюю его позицию в словаре
                {
                    char nextLastChar = prefix.charAt( prefix.length() - 1 );
                    prefixItem.word = prefix.substring( 0, prefix.length() -1 ) + (++nextLastChar); // готовим следующую не строку
                    int pos2 = Arrays.binarySearch( wordArr, pos1, wordCnt, prefixItem );  // ищем последнее вхождение префикса в словаре
                    if ( pos2 < 0)
                        pos2 = -pos2 -1;
                    if ( pos2 > wordCnt)
                        pos2 = wordCnt;
                    summaryWordCount += pos2 - pos1;
                    list = partialSort( 10, list, wordArr, pos1, pos2 );
                    for( WordItem item: list )
                        System.out.printf( "%6d %s\n", item.count, item.word );
                }
            }
            brd.close();
            System.out.printf( ">>> Длительность обработки %,f сек., средний размер выборки по каждому префиксу %d\n",  1e-9 * (System.nanoTime() - start), summaryWordCount / prefCnt);
        }
    }
  • Какую сортировку применять?

    @odissey_nemo
    longclaps: artshelom:

    Посмотрел и я, критик строгий, на творение творца названием из этого списка антонимов. Мне лично импонирует 7-й номер.

    Скажу сразу - мне лично творение понравилось. Кратко, мощно, грамотно. Быстрее моего "древнего" подхода практически на порядок (хэш - 4-5 секунд. двоичный -22 секунд). Не уверен, что код создан без Инет-поиска, но сути это не меняет.

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

    И, наконец, о главном. Хеш-словарь работает в разы, а то и на порядок быстрее двоичного поиска. И это понятно. Ведь скорость доступа к данным в Хэш-таблице - константа, а при двоичном поиске - двоичный логарифм.

    На этой бравурной ноте можно было бы и закончить послание, но что-то меня заело. Неужели, думаю, старые проверенные методы обязаны просто вот так вот уступить новому, неисследованному? И решил посмотреть вглубь, без кислорода.

    И обнаружил интересные вещи! Оказывается, число элементов в рабочей хэш-таблице оказалось ... ровно 150 000!!! Т.е. равно всему числу тестовых слов! Что невероятно, если тестовая последовательность слов создавалась без вытаскивания синтетических "слов" из той же хэш-таблицы. Ведь в хэш-таблицу попадали все (ВСЕ) префиксы, созданные из элемента словаря. Казалось бы, в общем случае, число хэш-ключей должно равняться числу исходных слов умноженных на среднюю длину слова. Но нет! Число уникальных ключей равно числу слов! А все слова состоят из 3 символов (a, b и c) в разных комбинациях. Синтетика!

    Решил, для начала, попробовать выборку, приближенную к реальности. Взял словарь Лебедева к браузеру Opera, что был под рукой (см. в архиве по ссылке). В нём было 142 000 русских слов, что близко к величине тестового словаря (150 000). Префиксы и их длины сгенерировал случайным отбором, общим числом, заданным в тесте (15 000).

    Провёл эксперимент. Результаты были ожидаемы, хотя и не кардинальны: двоичный поиск сработал чуть быстрее, а хэш медленнее, 5-6 секунд вместо 3-4. И, что логично, хэш-таблица резко выросла в размерах, стала около 500 000 вместо 150 000 ранее. И создавалась она теперь раза в два дольше, чем осуществлялась сортировка массива.

    На этом уже можно было бы ставить точку. С резюме: хэш-таблица по любому сработала много быстрее двоичного поиска. Но ведь заело!

    Стал разбираться в алгоритме longclaps. Удивило использование простой частичной сортировки вставкой. Решил опробовать. Это же сортировка, а сортировкам и противопоставлялся поиск по хэш-таблице. Это же наше, сортировщиков, всё!

    Ранее (см. переписку ) думал и утверждал, что тип сортировки при поиске всех соответствующих префиксу слов не должен бы влиять на общую длительность алгоритма. Реализовал в своём алгоритме чудо от longclaps, и - новое чудо! Алгоритм заработал за время сопоставимое с хэш-поиском!!! Т.е. те же секунды!

    Итак, теперь двоичный поиск работает не медленнее хэш-таблицы. Но резко меньше (в разы, если не больше) потребляет памяти. Ведь используется только один, простейший, массив объектов. Т.е. дело было не в бобине, а неправильном решении по использованию стандартной сортировки, вместо частичной с одним проходом по словам, включающим префикс.

    Можно оптимизировать память и дальше. Скажем, использовать общий массив символов, куда считать весь файл, а слова и префиксы хранить в Java 8 Segment (avax.swing.text.Segment), легко переносимый в более ранние версии. Тогда не будет отдельных строк вообще ни в словах, ни в префиксах. Можно отказаться от объектов вообще, сортировать только индексы. Но это уже сильно затуманит код.

    Посему большое спасибо и автору вопроса за тему и longclaps'у за ясность мыслей. Но от двоичной сортировки отказываться ещё рановато)))

    Исправленный Java код комментарием ниже. И в нём есть одна логическая неувязочка, которую уже лень устранять.
  • Какую сортировку применять?

    @odissey_nemo
    artshelom: Посмотрел. Понравилось. Сделано классически, без оптимизации. Вполне возможно, более универсальное.

    Исправил свой код. На моём Lenovo ThinkPad T4400 работает 22-24 секунды с выводом или без вывода, разница полсекунды. Быстрее с этим подходом уже не сделаешь. Надо думать дальше, в сторону укладки данных в другом виде, сразу готовом к выдаче. Или многопоточность. Интересно сравнить массив и дерево на этом тесте.

    На другом компьютере вполне может срабатывать за 5-10 секунд.
    Кстати, средний размер набора слов, содержащего префикс, 3750 слов. Что не тривиально, наверное. Т.е. тест - вырожденный. И набор букв какой-то... японский, 3 буквы)))
  • Какую сортировку применять?

    @odissey_nemo
    artshelom: binarySearch возвращает либо чётко самый ПЕРВЫЙ индекс со словом, совпадающим с префиксом, либо, если нет такого, то отрицательное значение самого раннего индекса, куда надо вставить наше искомое значение минус единица. Т.е. если возращено -1, то вставлять можно было бы в самое начало списка (индекс 0), -2 в индекс 1 и т.д., по возрастанию. На деле это значит, что binarySearch возвращает всегда точную позицию самого ранней позиции префикса в лексикографически отсортированном массиве (-1). Или укажет за границу массива (-array.length() -1).

    Итак, самая первая позиция префикса найдена точно! Или префикса вообще нет! Если он есть, берём до 10 первых лексикографических, начинающихся с искомого префикса. Т.к. сортировать можно либо лексикографически, либо по мощности (частоте). Для поиска по префиксу подходит только лексикографическая сортировка, естественно.

    Если в ответе требуется выводить ответ сортированный по мощности (этого в условии не уловил, похоже), т.е. частоте, то будем (всё равно) сортировать основной массив лексикографически, затем забирать все слова в массиве с префиксами, затем их сортировать и выдавать до 10 первых. Это и будет правильный ответ. Полагаю, на времени результата это не скажется никак.

    Из интереса возьму Вашу тестовую выборку и завтра проверю. Спасибо за тренировку :o)

    P.S. Ошибки возможны, тестировал на выборке в 10 слов и 5 префиксов. Это к слову о пользе тестирования.
    P.P.S. Ошибка понятно, не учёл, если префикс лексикографически выше последнего слова в словаре. Это надо обрабатывать, как пустой результат, т.е. пропускать и переходить дальше, да!
  • Почему hashset добавляет одинаковые объекты?

    @odissey_nemo
    Arti-Jack: хорошо. Может, кто ещё наткнётся и будет не зря. Ничто не Земле не проходит бесследно)))
  • Какую сортировку применять?

    @odissey_nemo
    Реализация алгоритма двоичным поиском. Тестовую выборку с утра запросил, но пока не получил.
    На небольшой тестовой подборке работает, оценить скорость без реальной выборки нельзя.
    Извиняюсь за смесь русских и английских комментариев. В какой-то момент забылся и переключился.
    package test;
    import java.io.*;
    import java.util.Arrays;
    import java.util.Comparator;
    import java.util.Date;
    
    /**
     * Created by nemo_odissey on 10.07.2017 12:45 for <a href="https://toster.ru/q/440261?utm_source=email_notifications&utm_medium=email&utm_content=mention&utm_campaign=notifications#comment_1428657" >Какую сортировку применять?</a>.
     */
    public class JapanEditor
    {
        /**
         * Compare by frequence and if equal, compare lexicographically
         */
        public static class ComparePrefixWithFreq implements Comparator
        {
            @Override
            public int compare( Object obj1, Object obj2 )
            {
                int cmp = ((WordItem) obj2).count - ((WordItem) obj1).count; // compare in reverse frequencies
                if ( cmp != 0 ) // texts are not equals
                    return cmp;
                return((WordItem)obj1).word.compareTo( ((WordItem)obj2).word ); // if freqs are equal, compare lexicographically
            }
        }
    
        /**
         * Class to store vocabulary item and make it comparable only  lexicographically
         */
        public static class WordItem implements Comparable
        {
            public String word;
            public int count;
    
            public WordItem( String word, int count )
            {
                this.count = count;
                this.word = word;
            }
    
            @Override
            public int compareTo( Object obj )
            {
                return this.word.compareTo( ((WordItem)obj).word );
            }
        }
    
        /**
         * Обработки ошибок НЕТ
         * @param args путь_к_файлу_с_данными, где хранится задание
         * @throws IOException
         */
        public static void main( String[] args ) throws IOException
        {
            long start = new Date().getTime();
            BufferedReader brd  = new BufferedReader( new FileReader(args[0]), 32 * 1024 );
            // читаем число слов
            int wordCnt = Integer.parseInt( brd.readLine() );
            WordItem[] wordArr = new WordItem[wordCnt];
            // Читаем все слова и их частоты
            for(int i = 0; i < wordCnt; i++)
            {
                String[] elems = brd.readLine().split( " " );
                wordArr[ i ] = new WordItem( elems[0], Integer.parseInt( elems[1] )  );
            }
            // сортируем массив словаря
            Arrays.sort( wordArr );
    
            // сортировщик по частоте
            ComparePrefixWithFreq compareWithFrequence = new ComparePrefixWithFreq();
    
            // считываем и обрабатываем каждый префикс один за другим
            int prefCnt = Integer.parseInt( brd.readLine() );
            System.out.printf( "Счётчик слов %d, счётчик префиксов %d\n", wordCnt, prefCnt );
            System.out.printf( "Словарь считан и отсортирован за %,d млс.\n\n", new Date().getTime() - start );
            int summaryWordCount = 0;
            WordItem prefixItem = new WordItem( null, 1 );
            for(int i = 0; i < prefCnt; i++)
            {
                String prefix = brd.readLine().trim();
                prefixItem.word = prefix;
                int pos = Arrays.binarySearch(wordArr, prefixItem ); // if positive, point to a word in vocabulary started from prefix or equal to it
                if ( pos < 0) // no precise prefix value found in vocabulary
                    pos = -(pos + 1); // pos to the first element starting from prefix
                if ( pos >= wordCnt) // префикс отсутствует в словаре
                    continue;
    
                if ( wordArr[pos].word.startsWith( prefix )) // Если префикс есть, ищем его конец в словаре
                {
                    char nextLastChar = prefix.charAt( prefix.length() - 1 );
                    prefixItem.word = prefix.substring( 0, prefix.length() -1 ) + (++nextLastChar); // готовим следующую не строку
                    int pos1 = Arrays.binarySearch( wordArr, pos, wordCnt, prefixItem );  // ищем последнее вхождение префикса в словаре
                    if ( pos1 < 0)
                        pos1 = -pos1;
                    if ( pos1 > wordCnt)
                        pos1 = wordCnt;
                    summaryWordCount += pos1 - pos;
                    // pos -> first word with prefix, pos1 -> first word without prefix
                    WordItem[] wordsWithPrefix = Arrays.copyOfRange( wordArr, pos, pos1 );
                    Arrays.sort( wordsWithPrefix, compareWithFrequence );
                    int wordWithPrefCnt = Math.min( wordsWithPrefix.length, 10 );
                    for( int j = 0; j < wordWithPrefCnt; j++ )
                        //System.out.printf("%s %d\n", item.word, item.count); // debug output
                        System.out.println( wordsWithPrefix[j].word );
                    System.out.println(""); // add empty line according to the task requirements
                }
            }
            brd.close();
            System.out.printf( ">>> Длительность обработки %,d млс., средний размер выборки по каждому префиксу %d\n", new Date().getTime() - start, summaryWordCount / prefCnt);
        }
    }
  • Какую сортировку применять?

    @odissey_nemo
    longclaps: Не понял, откуда такие сложности привиделись? Зачем кэширование и/или хэширование? Для демонстрации способностей и теоретических знаний? Мудр кто знает нужное, а не многое (с) не моё.

    Сортировка тут - один раз. Это далеко не заполнение и формирование дерева с его структурами и адресами. Создал массив фиксированного размера, затем линейно заполняешь объектами и 1 (один) раз сортируешь.

    Двоичный поиск работает методом деления пополам, т.е на 4 миллиарда элементов в среднем будут 16 обращений к линейной таблице объектов по индексу, не по ссылкам. Явно не медленнее обхода по дереву. Собственно, это логический аналог обхода по дереву.

    Сортировать часто придётся только конкретный ответ, т.е. не более 10 элементов на один ответ, в среднем сортировать по 5 элементов (предположительно). Можно для таких целей взять экзотик-сортировку для сверхкоротких выборок.

    Про третью стадию либо я не понял Вас, либо Вы не поняли (писал кратко).

    Ответ длиннее чем описание.

    Дайте мне тестовую выборку и говорить дальше не придётся (пусть говорят пушки))). Сложные решения - для простых задач?

    P.S. Преимущество при использовании дерева есть - это более универсальное решение, которое можно использовать при решении других задач, связанных с поиском. По жизни не раз решал реальные задачи двоичным поиском и сложные алгоритмы не требовалось. Времени это вообще не занимало. Впрочем, всё зависит от тестовой выборки. Но, зная размеры максимальных словарей (десятки тысяч слов в реальности), можно предположить, что задача будет идти секунды.
  • Какую сортировку применять?

    @odissey_nemo
    Решение похоже на верное. Но можно сделать ещё проще.

    1. Отсортировать стандартной сортировкой 1-ю часть списка (со словами и частотой) как массив объектов {строка, частота} в естественном лексическом порядке.

    2. Для второй части списка (с начальными частями слов) двоичным поиском искать место, куда вставить искомое начало слова. Результатом будет индекс первого слова в отсортированном массиве, начинающегося с этого префикса.
    3. Пройтись последовательно вниз по массиву, выбрав максимум 10 слов с префиксом (или менее 10, как уж придётся). Найденные слова отсортировать той-же сортировкой (потери на универсализм будут не существенны, полагаю) по убыванию частоты и длины слов и выводить на out.

    Должно получиться быстро, хотя и не столь внушительно, как с применениями деревьев)))
  • Как упаковать массив int в массив char максимально компактно?

    @odissey_nemo
    На случай, если понадобится самому решать, в какие массивы преобразовывать, то скажу: по моим ощущениям, лучше всего хранить любые примитивные данные в байтовых массивах. Т.к. это базовый тип, через который так или иначе проходят все прочие игры с преобразованием примитивных типов. Ниже базовый класс для упаковки/распаковки любых примитивных значений в массивы байты и ... массивы int. int, подозреваю, работает быстрее, с т.з. нагрузки на процессор, конечно.

    package ru.ts.common.records;
    
    /**
     * Utility methods for packing/unpacking primitive values in/out of bytes and
     * integer arrays using <b>big-endian</b> byte ordering.
     */
    public class Bits
    {
    
    	/*
    	 * Methods for unpacking primitive values from byte arrays starting at given
    	 * offsets.
    	 */
    
    	public static boolean getBoolean(byte[] b, int off)
    	{
    		return b[ off ] != 0;
    	}
    
    	static int[]	BYTE_MASK;
    
    	static int[]	BYTE_SHIFT;
    	static
    	{
    		BYTE_MASK = new int[] { 0xFF, 0xFF00, 0xFF0000, 0xFF000000 };
    		BYTE_SHIFT = new int[] { 0, 8, 16, 24 };
    	}
    
    	static byte getByte(int[] b, int off, int ind)
    	{
    		return (byte)((b[ off ] & BYTE_MASK[ ind ]) >> BYTE_SHIFT[ ind ]);
    	}
    
    	static boolean getBoolean(int[] b, int off, int ind)
    	{
    		return ((b[ off ] & BYTE_MASK[ ind ]) >> BYTE_SHIFT[ ind ]) != 0;
    	}
    
    	public static char getChar(byte[] b, int off)
    	{
    
    		return (char) (((b[ off + 1 ] & 0xFF) << 0) + ((b[ off + 0 ] & 0xFF) << 8));
    	}
    
    	static int[]	CHAR_MASK;
    	static int[]	CHAR_SHIFT;
    	static
    	{
    		CHAR_MASK = new int[] { 0xFFFF, 0xFFFF0000 };
    		CHAR_SHIFT = new int[] { 0, 16 };
    	}
    	/**
    	 * 
    	 * @param b bit array containing of char looked for
    	 * @param off offset to the array
    	 * @param ind index of char packed into int. May be 0 or 1 ONLY!!!
    	 * @return character stored in the array
    	 */
    	public static char getChar(int[] b, int off, int ind)
    	{
    		return (char) ( (b[off] & CHAR_MASK[ind]) >> CHAR_SHIFT[ind]);
    	}
    
    	static short getShort(byte[] b, int off)
    	{
    		return (short) (((b[ off + 1 ] & 0xFF) << 0) + ((b[ off + 0 ] & 0xFF) << 8));
    	}
    
    	/**
    	 * the same as char
    	 * @param b
    	 * @param off
    	 * @param ind	index of short packed into int may be 0 or 1 ONLY
    	 * @return
    	 */
    	static short getShort(int[] b, int off, int ind)
    	{
    		return (short) ( (b[off] & CHAR_MASK[ind]) >> CHAR_SHIFT[ind] );
    	}
    
    	public static int getInt(byte[] b, int off)
    	{
    		return ((b[ off + 3 ] & 0xFF) << 0) + ((b[ off + 2 ] & 0xFF) << 8)
    		        + ((b[ off + 1 ] & 0xFF) << 16) + ((b[ off + 0 ] & 0xFF) << 24);
    	}
    
    	static int getInt(int[] b, int off)
    	{
    		return b[ off ];
    	}
    
    	static float getFloat(byte[] b, int off)
    	{
    		int i = ((b[ off + 3 ] & 0xFF) << 0) + ((b[ off + 2 ] & 0xFF) << 8)
    		        + ((b[ off + 1 ] & 0xFF) << 16) + ((b[ off + 0 ] & 0xFF) << 24);
    		return Float.intBitsToFloat(i);
    	}
    
    	static float getFloat(int[] b, int off)
    	{
    		return Float.intBitsToFloat( b[off] );
    	}
    
    	static long getLong(byte[] b, int off)
    	{
    		return ((b[ off + 7 ] & 0xFFL) << 0) + ((b[ off + 6 ] & 0xFFL) << 8)
    		        + ((b[ off + 5 ] & 0xFFL) << 16)
    		        + ((b[ off + 4 ] & 0xFFL) << 24)
    		        + ((b[ off + 3 ] & 0xFFL) << 32)
    		        + ((b[ off + 2 ] & 0xFFL) << 40)
    		        + ((b[ off + 1 ] & 0xFFL) << 48)
    		        + ((b[ off + 0 ] & 0xFFL) << 56);
    	}
    
    	public static long getLong(int[] b, int off)
    	{
    		return ((long)b[ off ] & 0xFFFFFFFFL) + ( ((long)(b[ off + 1 ])) << 32L);
    	}
    
    	public static double getDouble(byte[] b, int off)
    	{
    		long j = ((b[ off + 7 ] & 0xFFL) << 0) + ((b[ off + 6 ] & 0xFFL) << 8)
    		        + ((b[ off + 5 ] & 0xFFL) << 16)
    		        + ((b[ off + 4 ] & 0xFFL) << 24)
    		        + ((b[ off + 3 ] & 0xFFL) << 32)
    		        + ((b[ off + 2 ] & 0xFFL) << 40)
    		        + ((b[ off + 1 ] & 0xFFL) << 48)
    		        + ((b[ off + 0 ] & 0xFFL) << 56);
    		return Double.longBitsToDouble(j);
    	}
    
    	public static double getDouble(int[] b, int off)
    	{
    		long j = ((long)b[ off ] & 0xFFFFFFFFL) + ( ((long)(b[ off + 1 ])) << 32L);
    		return Double.longBitsToDouble(j);
    	}
    
    	/*
    	 * Methods for packing primitive values into byte arrays starting at given
    	 * offsets.
    	 */
    
    	static void putBoolean(byte[] b, int off, boolean val)
    	{
    		b[ off ] = (byte) (val ? 1 : 0);
    	}
    
    	
    	static void putBoolean(int[] b, int off, int ind, boolean val)
    	{
    		b[ off ] &= ~(BYTE_MASK[ind]);
    		b[ off ] |= (byte) (val ? 1 : 0) << BYTE_SHIFT[ind];
    	}
    	
    	static void putByte(int[] b, int off, int ind, byte val)
    	{
    		b[ off ] &= ~(BYTE_MASK[ind]);
    		b[ off ] |= val << BYTE_SHIFT[ind];
    	}
    
    	static void putChar(byte[] b, int off, char val)
    	{
    		b[ off + 1 ] = (byte) (val >>> 0);
    		b[ off + 0 ] = (byte) (val >>> 8);
    	}
    
    	static void putChar(int[] b, int off, int ind, char val)
    	{
    		b[off] &= ~CHAR_MASK[ind];
    		b[off] |= ((short)val) << CHAR_SHIFT[ind];
    	}
    
    	static void putShort(byte[] b, int off, short val)
    	{
    		b[ off + 1 ] = (byte) (val >>> 0);
    		b[ off + 0 ] = (byte) (val >>> 8);
    	}
    
    	static void putShort(int[] b, int off, int ind, short val)
    	{
    		b[off] &= ~CHAR_MASK[ind];
    		b[off] |= val << CHAR_SHIFT[ind];
    	}
    
    	public static void putInt(byte[] b, int off, int val)
    	{
    		b[ off + 3 ] = (byte) (val >>> 0);
    		b[ off + 2 ] = (byte) (val >>> 8);
    		b[ off + 1 ] = (byte) (val >>> 16);
    		b[ off + 0 ] = (byte) (val >>> 24);
    	}
    
    	static void putInt(int[] b, int off, int val)
    	{
    		b[ off ] = val;
    	}
    
    	static void putFloat(byte[] b, int off, float val)
    	{
    		int i = Float.floatToIntBits(val);
    		b[ off + 3 ] = (byte) (i >>> 0);
    		b[ off + 2 ] = (byte) (i >>> 8);
    		b[ off + 1 ] = (byte) (i >>> 16);
    		b[ off + 0 ] = (byte) (i >>> 24);
    	}
    
    	static void putFloat(int[] b, int off, float val)
    	{
    		int i = Float.floatToIntBits(val);
    		b[ off ] = (i);
    	}
    
    	public static void putLong(byte[] b, int off, long val)
    	{
    		b[ off + 7 ] = (byte) (val >>> 0);
    		b[ off + 6 ] = (byte) (val >>> 8);
    		b[ off + 5 ] = (byte) (val >>> 16);
    		b[ off + 4 ] = (byte) (val >>> 24);
    		b[ off + 3 ] = (byte) (val >>> 32);
    		b[ off + 2 ] = (byte) (val >>> 40);
    		b[ off + 1 ] = (byte) (val >>> 48);
    		b[ off + 0 ] = (byte) (val >>> 56);
    	}
    	
    	public static void putLong(int[] b, int off, long val)
    	{
    		b[ off ] = (int) (val & 0x00000000FFFFFFFFL);
    		b[ off + 1 ] = (int) ( val >>> 32);
    	}
    
    	public static void putDouble(byte[] b, int off, double val)
    	{
    		long j = Double.doubleToLongBits(val);
    		b[ off + 7 ] = (byte) (j >>> 0);
    		b[ off + 6 ] = (byte) (j >>> 8);
    		b[ off + 5 ] = (byte) (j >>> 16);
    		b[ off + 4 ] = (byte) (j >>> 24);
    		b[ off + 3 ] = (byte) (j >>> 32);
    		b[ off + 2 ] = (byte) (j >>> 40);
    		b[ off + 1 ] = (byte) (j >>> 48);
    		b[ off + 0 ] = (byte) (j >>> 56);
    	}
    
    	public static void putDouble(int[] b, int off, double val)
    	{
    		long j = Double.doubleToLongBits(val);
    		b[ off ] = (int) (j & 0xFFFFFFFFL);
    		b[ off + 1 ] = (int) (j >>> 32L);
    	}
    }
  • Как сделать ограничение по времени на время жизни потока в Java?

    @odissey_nemo
    Есть join с параметром - кол-вом миллисекунд до конца ожидания или же завершения нити, к которой исполняется join. Можно использовать его, чтобы не заснуть навсегда. И по выходу проверять, остановилась ли тестируемая нить, или же просто вышло заданное время ожидания нити. И далее реагировать в соответствии с логикой алгоритма.
  • История местоположения google, как получить даты посещения конкретной точки?

    @odissey_nemo
    HelpSophie: Андроид не держу. Гы-Пы-Эс не пользую. Хватает и мозга для ориентирования. Сим-карта только если корпоративная, по необходимости.
  • История местоположения google, как получить даты посещения конкретной точки?

    @odissey_nemo
    HelpSophie: наш человек! С маленьких побед придёт и большая! С Днём Победы!
  • Ваши действия, если джуниор не успевает выполнить задачу?

    @odissey_nemo
    Павел Перминов: Нормальный РФ-подход к РФ-людям. Ничего личного, как говорится) В нормальных РФ-конторах, где оборот людей круговой, это норма, согласен.
    Лично ищу не РФ-конторы, где имеет значение и человеческий фактор и способность работать в коллективе. Иногда получается, иногда нет. Если получается, то Ваш подход там не сработает. Если не получается - он только и применяется. Каждому - своё. И пока ещё есть выбор.
  • Какой самый оптимальный размер шрифта для редактора кода?

    @odissey_nemo
    Больше внимания стоит обратить на методы структурирования текста, т.е. как скобки ставить, табуляции, отделять ли описание от названия, разделять запятые в перечислении параметров пробелами и т.д. Потом долгое время работаешь с одними настройками, вдруг увидишь другие, понравятся, переделаешь и на новых также работаешь длительное время, годами.
  • Чем обоснован экспоненциальный рост времени выполнения куска кода при увеличении размера массива в 10 раз?

    @odissey_nemo
    enq3: Возможно, что в начале опережающий кэш формируется, а потом используется. В общем, надо специалистов по конкретному процессору спрашивать.

    А тестировать стоит каждый раз на задаче, запускаемой вновь, через промежуток времени. Или ввести какую-то подготовительную работу над памятью перед тестированием. И тогда результаты будут если и не полностью достоверными, то более реалистичными.

    Ведь, как известно экспериментально, второй проход по одним и тем же данным (если они не слишком велики) на современных микропроцессорах всегда выполняется быстрее. А так было не всегда. Помню, на PDP-11 ещё можно было делать самомодифицируемый код в алгоритмах на ассемблере (для краткости кода, например, в классическом алгоритме Бризенхема) и процессор на это не влиял. А уже та же логика на Intel 80286 давала сбои. Причём под отладчиком всё было нормально, а без него - самомодификация не работала. А кэш тогда и был-то всего в несколько команд.

    Самый классический пример - это чтение файла. Он всегда второй раз читается быстрее. И Windows и Unix (он первым это придумал, кстати) кэшируют обращения к файловой системе. В Windows именно в этот системный кэш в основном и девается оперативная память. Смотришь в диспетчере задач Вындорза - простые задачки много места не занимают, а памяти - нету! Разве только сервисы что-то там своё могут забирать немеряно?