Как стать автором
Обновить

Комментарии 45

Браво. Читал с удовольствием.

но меня задолбало это это набирать

Ну есть же замена в редакторе, это быстро.

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

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

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

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

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

а потому современные упаковщики, сначала смотрят тип данных для упаковки, а потом выбирают стратегию упаковки именно исходя из полученного анализа

а потому современные упаковщики, сначала смотрят тип данных для упаковки, а потом выбирают стратегию упаковки именно исходя из полученного анализа

Нет же. Они гонят все в gzip или те что более продвинутые в zstd. И не парятся.

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

кстати PNG по сути как раз сжимает данные в зависимости от контекста, а вот насколько хорошо, то уже зависит от реализации, поэтому я обычно за paint.net и photoshop еще файлы дожимаю с помощью Pingo. У меня на сетевом диске есть библиотека PNG файлов для рисования всякого, размер около 4 Гб, я прогнал как-то ее через Pingo и уменьшил размер до 3.2Гб.

Подобрать более подходящий алгоритм под паттерн данных на стадии проектирования можно. И так делают иногда. Хотя как правило все равно просто берут gzip или zstd.

Это все равно безмерно далеко от анализа текущего потока и подбора чего-то под него. Один раз спроектировали, написали и оно крутится годами.

PS: Правильная настройка словаря для zstd дает больше чем практически все остальное (работающее со сравнимой скоростью) на почти любом паттерне данных.

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

В подавляющем большинстве случаев берут гзип и не парятся. Оно того не стоит. В остальных случаях стоит подумать о чем-то вроде настройки словаря zstd.

И это все равно не "сначала смотрят тип данных для упаковки, а потом выбирают стратегию упаковки именно исходя из полученного анализа".

То что кто-то не слишком умный это понятно, но мы же не такие, а значит выбор стратегии имеет место быть. Ну и разговор идёт об обычных архиваторах, а не о бизнес-моделях, а там zip/7z/rar где Deflate совсем не единственный метод, скорее уж вы попадёте на LZMA.

Лично я для себя пользуюсь zpaq (m5) и 7zip(bzip2 или ppmd) и за 50 лет ни разу не пользовался ни gzip ни zstd.

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

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

zpaq
zpaq

Пример тупой сортировки (не стоит её повторять):

#include

#define N 10

int main()
{
int vec[N] = {1, 7, 3, -7, -1, 7, 9, -2, 5, 8};
for (auto i = 0; i < N - 1; ++i)
if ((vec[i] > vec[i + 1])) {
std::swap(vec[i], vec[i + 1]); i = -1;
}
for (auto i = 0; i < N; ++i) std::cout << vec[i] << "\t";
return EXIT_SUCCESS;
}

Никак не пойму, зачем писать auto i =0? int и на один символ короче, и нагляднее...

Согласен, это победитель)

По сложности он идентичен самому первую варианту в статье. Так что они тут делят первое место по тупости :)

По идее у Bogosort тупость всё же чуть выше (если не смотреть на память). Дело в сохранении информации — ваш алгоритм гарантированно проверяет каждый вариант максимум один раз, и с каждым шагом он всё ближе к получению "правильного" массива; в то же время Bogosort не ограничен от "топтания на месте" ничем. Так что O(n*n!) у вас соответствует максимальному времени сортировки, а у Bogosort — среднему… впрочем, его преимущество в том, что памяти почти не нужно.

Ох, насколько же приятно выглядит мобильная википедия на десктопе!

Ой. Простите. Копипастил ссылку с телефона, забыл .m. убрать.

Редактировать коммент уже не могу. Надеюсь это не проблема? Вот ссылка на не мобильную версию вики.

https://ru.wikipedia.org/wiki/Bogosort

Блин, как начал читать статью, тут же подумал об этом алгоритме, но оказалось, что его уже придумали (

Я больше SlowSort предпочитаю


никакого рандома
экспоненциальная сложность

Моя номинация на самую тупую сортировку:

Java
import java.util.Arrays;

public class Test {

  public static void main(String[] args) {

    final int[] arr = {1, 7, 3, -7, -1, 7, 9, -2, 5, 8};
    final int[] sorted = naiveSort(arr);

    System.out.println(Arrays.toString(arr));
    System.out.println(testSorted(arr));
    System.out.println(Arrays.toString(sorted));
    System.out.println(testSorted(sorted));

  }

  private static int[] naiveSort(int[] arr) {

    final int[] sorted = new int[arr.length];
    final boolean[] checked = new boolean[arr.length];
    Arrays.fill(checked, false);

    for (int i = 0; i < arr.length; i++) {
      sorted[i] = findMin(arr, checked);
    }

    return sorted;
  }

  private static int findMin(int[] arr, boolean[] checked) {
    int min = Integer.MAX_VALUE;
    int minInd = 0;

    for (int i = 0; i < arr.length; i++) {
      if (!checked[i] && arr[i] <= min) {
        min = arr[i];
        minInd = i;
      }
    }

    checked[minInd] = true;
    return min;
  }

  private static String testSorted(int[] arr) {

    for (int i = 0; i < arr.length - 1; i++) {
      if (arr[i] > arr[i + 1]) {
        return  "Array is not sorted";
      }
    }

    return "Array is sorted";
  }

}

Хотя это скорее не тупая, а "наивная". Т.е. если бы я ничего не знал о программировании (ну, кроме синтаксиса), я бы написал именно так. Даже то что можно просто поменять местами два элемента - это какая-то иезуитская хитрость :) Я бы наверно сам не допёр, по крайней мере, не сразу.

это ж по сути сортировка выбором, только складывают не в отдельный массив, а в начало/конец сортируемого, сдвигая неотсортированное.

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

это ж по сути сортировка выбором

:)

У меня самый простой вариант:

    public void sort(List<Integer> list) {
        while (!isSorted(list)) {
            Collections.shuffle(list);
        }
    }

    private boolean isSorted(List<Integer> list) {
        for (int i = 0; i < list.size() - 1; i++) {
            if (list.get(i) > list.get(i + 1))
                return false;
        }

        return true;
    }

У вас он еще и некорректный, потому что если числа повторяются, список никогда не отсортируется :)

А есть Stalin Encryption? ?

Конечно, это юмористическая статья, но подобная сортировка оптимизированная под размер массива (4-9 элементов) существует в прод-коде. Если не изменяет память, разработчики гугла применили такое в одной из библиотек и увеличили скорость сортировки внутри sql-запросов до 30 %.

Реализация libcxx обрабатывала несколько конкретных случаев особым образом. Коллекции длиной 5 или меньше сортировались при помощи специальных самописных сортировок на основе сравнений.
https://habr.com/ru/articles/662181/

Вероятно вы правы. Не удивительно. Идея же лежит на поверхности.

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

который я где-то пролюбил

fixed. Вот среднее число сравнений если каждый раз выбирать индексы жадно (максимизируя min(len(lss), len(gtr)). Было бы хорошо если бы обновили график.

ссылка на код

[1.0, 2.6666666666666665, 4.666666666666667, 6.933333333333334, 9.577777777777778, 12.39047619047619, 15.406795634920634]

более тупое

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

какое наименьше (в среднем) число вопросов (сравнений двух элементов) нужно задать что бы отгадать загаданную перестановку

Подержите моё пиво

Гениально! В то время как лучшие умы человечества пытаются превзойти n log n, этот код при сортировке отрицательных чисел должен выдать ответ ещё до вызова!

Также известно как delay sort

Автор чем-то пьян. Пьян идеей ?

О, когда весной изучал работу нового поколения псевдоразумных нейросетей архитектуры трансформера (GPT3 / GPT 4 и их многочисленные аналоги), в частности остановился на том, как они сортируют списки или занимаются простым счетом если задать им такую задачу в чистом виде или как часть более общей.
В частности что они без проблем справляются с короткими списками, но начинают ошибаться и сильно тупить (даже если указывать им на ошибки и пытаться помочь/подсказать) если список становится длиннее (в зависимости от конкретной реализации и "размера" сети = количества ее "параметров"/весов, это происходит где-то в диапазоне от 7-10 элементов и до нескольких десятков)
И пришел к выводу, что нейросети в процессе "тренировки" самостоятельно сформировали внутри себя очень специфические алгоритмы. Которые скорее всего представляют что-то очень похожее на описанное вами! Конкретно для случая сортировки.


Вот тут про это немного писал в комментариях:
https://habr.com/ru/companies/ods/articles/716918/comments/#comment_25509482
https://habr.com/articles/729966/#comment_25509056 (тут 1й пример, где прошу нейросеть на базе GPT-4 отсортировать буквы по алфавиту)


Что-то похожее(хотя и немного другое) происходит и с математическими операциями, когда подобная нейросеть пытается выполнять математические операции — там размерность чисел не ограничена, но результат получается "примерный".


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


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


Вот представьте, что вы программируете, но у вас в распоряжении есть только один очень дурацкий язык программирования, в котором ВООБЩЕ отсутствуют циклы и нет доступа к оперативной памяти для хранения переменных(зато констант прямо в код нафигачить можно почти неограниченно) и даже встроенных базовых математический операций(сложение, умножение и т.д.) в языке нет. Но зато if… then… else и их аналоги (Case, Select и т.д.) можно фигачить в код тоже почти в неограниченных количествах.
И вам вот с таким "инструментарием" нужно отсортировать массив, или сосчитать количество элементов в некотором множестве или выполнять математические операции и т.д.


И вот тогда, подобные "тупые" алгоритмы, окажутся далеко неплохим вариантом, а вероятно одним из лучшим (из возможных в конкртеных ограниченных условиях). А вот это:


А факториал растет очень быстро, значит наши функции будут становиться все длиннее, отнимая не только вычисления, но и память — ее нам тоже потребуется O(n!). Не для хранения данных (мы же их даже никуда не сохраняем), а для самого алгоритма.

Становится не багой (простыни говнокода из бесконечной лапши IF-ов, вместо считанных байт для хранения нескольких переменных и обработки в цикле и вызова функций рекурсией), а киллер-фичей в условиях когда этих самых байт ОЗУ тупо нет в принципе (точнее не можем в него ничего писать во время исполнения "кода"), зато мегабайты кода — вообще не проблема.

Самая крутая сортировка — квантовая. Имея квантовый источник случайного шума, можно за O(n) получить случайную перестановку массива. Потом, опять же за O(n), можно, как верно заметил автор, проверить, а не отсортирован ли массив. Если нет, то надо, всего-лишь уничтожить вселенную. В результате (если принять многомировую интерпретацию квантовой физики) останется хотя бы одна вселенная, в которой массив отсортирован за O(n). Вот, мы и изобрели линейный алгоритм сортировки!

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

Всмысле? Да будь там числа хоть 0,1 — все равно надо все числа обойти. O(n) получается.

Не получается. O(1) означает, что существует такое константное k, что алгоритм заканчивается за k шагов для всех размеров входа. Целых чисел фиксированное количество (2^32 штук например), а значит, такое k существует.

Если кажется ну совсем сюром, тогда вот другой (на этот раз вполне себе практический, даже по памяти приемлемый): алгоритм сортировки «за O(n)», если диапазон чисел не очень велик и все числа в массиве уникальны (на самом-то деле он тоже O(1), ну да назовем это «похожим на O(n)»). Например, если у нас есть не более 1000 уникальных элементов в диапазоне 0..999, можно их отсортировать за ~2000 шагов: берем зануленную битовую карту на 1000 битов (это всего-то 125 байтов), дальше идем по входному массиву и взводим в 1 бит, соответствующий очередному числу. В конце проходим по битовой карте и выплевываем в качестве результата позиции тех битов, где 1 (тут огромный простор для оптимизаций: можно проскакивать те 8-байтовые группы, где все нули например). Похожий алгоритм широко используется в СУБД.

Нет же. 32 битных чисел — конечное число. Массивов из них — бесконечное. Не существует такого k. Допустим оно есть, а я вам дам массив из k+1 числа. И даже не любой массив, а очень ограниченный — все числа там нули и только одно число больше нуля. За k шагов вы даже это ненулевое число не всегда найдете, а найти его надо, ведь оно может быть любым. А оно может быть на любой из k+1 позиции.


Да, если у вас чисел строго ограниченное количество, то можно, конечно, и сову O(1) натянуть на глобус ассимптотики. Но это солипсизм какой-то получается. Такто, у вас всегда ограниченное количество данных, ибо компьютеры конечны. Поэтому счтают скорость роста от размера входных данных, хоть бы этот размер и ограничен, что не строго соответствует математическому определению.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории