Задать вопрос
  • Какую сортировку применять?

    @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 именно в этот системный кэш в основном и девается оперативная память. Смотришь в диспетчере задач Вындорза - простые задачки много места не занимают, а памяти - нету! Разве только сервисы что-то там своё могут забирать немеряно?
  • Чем обоснован экспоненциальный рост времени выполнения куска кода при увеличении размера массива в 10 раз?

    @odissey_nemo
    Если дело в функции random, то циклы разной длины, но без использования памяти под сохранение сгенерированных рандомных данных, должны давать нелинейное изменение времени исполнения. А если время линейное, то и дело - в памяти, вернее, её утилизации процессором.
  • Чем обоснован экспоненциальный рост времени выполнения куска кода при увеличении размера массива в 10 раз?

    @odissey_nemo
    Спасибо за пример.

    Но, если поменять местами циклы, то уже первый способ (теперь уже второй) будет на порядок (20 раз) быстрее. Всё дело в кэшах, не иначе. Кэши - они разные. ideone.com/EsvPAu
  • Стоит ли изучать Swing?

    @odissey_nemo
    JavaFX пока что мышь. И не факт, что вырастет до размеров мамонта.
  • На каком языке писать приложение?

    @odissey_nemo
    Полагаю, Delphi переживёт все называемые здесь непонятные фреймворки, оболочки и библиотеки, за исключением Java и JavaScript. Вот они (и Delphi) будут жить вечно (в пределах субъективного мироощущения), но в разных объёмах и задачах :o)
  • Как осуществить сравнение и добавить строку в txt файл?

    @odissey_nemo
    Вопрос не понятен. Если есть JTable, значит есть и программа, которая уже привязывает вводимые данные в нужную строку. Но зачем txt? Зачем его выгружать? И даже загружать, видимо?

    Если следует искать в текстовом файле и его же модифицировать, то откуда берётся строка поиска и из чего она состоит?

    Если задача просто найти дату связанную с каким либо именем в текстовом файле и добавить в результирующий текстовый файл дополнительный столбец с дополнительными данными, то можно:

    а) считать исходный txt,

    б) перевести его в какую-либо структуру, обеспечивающую поиск по, например, имени и дате. Подойдёт даже Hashtable, ключом которой будут текстовая сумма искомых столбцов по каждой строке, однообразно слитых друг с другом в строку, и не повторяющиеся. А значением Hashtable будут все поля из исходного txt в форме массива строк, для простоты,

    в) вводить откуда либо, пусть и из другого txt поисковые группы, связанные с новыми данными, переводя их в форму, соответствующую формату ключей нашего Hashtable,

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

    д) вывести в новый текстовый файл все значения переработанного Hashtable, преобразуя их в принятый в txt формата.

    Если же искать надо в JTable - это уже GUI, а оно у Вас уже есть.

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

    P.S. Вряд ли проблема "больших данных" тут возникнет, если уж ввод новых данных осуществляется вручную.
  • Какой java библиотекой конвертировать multi-strip tiff на pdf?

    @odissey_nemo
    @Mnobody: Понятно. Видимо, одна библиотека и для чтения и для генерации PDF. Это логично и рационально. В PNG мульти-стрипов не бывает. Хотя мульти-срезы можно организовать. Как превью для разного масшатаба. Тоже и с JPG. Но базовый растр (1:1) всегда один. Поэтому его и считывают стандартные Java либы всегда хорошо.

    Вы упомянули просто TIFF , а это самый навороченный формат. Для научных целей созданный. И мульти-стрипы там есть. Вернее - тайлы. Хотя стрипы - тоже, как тайлы шириной во весь растр - чаще. Поэтому и решил прописать своё небольшое видение :o)

    Но понимаю, что вопрос был не в этом. Хорошо, что всё решилось, и решилось просто - это главное.
  • Как получить доступ к объекту класса?

    @odissey_nemo
    Вопрос не понятен. Буквально, по тексту, Вы хотите из самого класса B (не его экземпляра, раз это не указано) вызвать непонятного типа и параметров функцию printText.
    Этого маловато для ответа. Специфицируйте требования к printText и условиям её вызова.
    Или просто унаследуйте B из A, и обеспечьте доступ к внутреннему JLabel.