LINUX.ORG.RU

Ответ на: комментарий от aho

Глаза поломать можно. Как этот код работает?

Вот нормальный, человекочитаемый вариант

(опрфун список-в-гистограмму* (список гистограмма)
        (если (пуст список) гистограмма
              (отныне ((голова-списка (первый-элемент список))
                       (хвост-списка (остаток список))
                       (элемент-гистограммы (элемент гистограмма))
                       (число-вхождений (элемента-в гистограмма)))
                      (если (совпадает голова-списка элемент-гистограммы)
                            (список-в-гистограмму* хвост-списка (составить (составить элемент-гистограммы (+ 1 число-вхождений)) (остаток гистограмма))) 
                            (список-в-гистограмму* хвост-списка (составить (составить голова-списка 1) гистограмма))))))


(опрфун список-в-гистограмму (список)
        (перевернуть (список-в-гистограмму* список NIL)))

* (список-в-гистограмму '())

NIL
*  (список-в-гистограмму '(1 1 1 1 2 2 2 3 4 4 5))

((1 . 4) (2 . 3) (3 . 1) (4 . 2) (5 . 1))

Сразу понятно как это работает и что чего делает. Ибо на лиспе лучшая документация --- это код.

P.S. Очень не хватает падежей. Пойду изобретать свой лисп с падежами и склонениями.

ugoday ★★★★★
()
Ответ на: комментарий от ugoday

Чтобы это взлетело:

(defmacro опрфун (&body body)
  `(defun ,@body))

(defmacro пуст (body)
  `(null ,body))

(defmacro совпадает (&body body)
  `(eq ,@body))

(defmacro если (condition &body body)
  `(if ,condition ,@body))

(defmacro первый-элемент (&body body)
  `(car ,@body))

(defmacro остаток (&body body)
  `(cdr ,@body))

(defmacro элемент (&body body)
  `(caar ,@body))

(defmacro элемента-в (&body body)
  `(cdar  ,@body))

(defmacro отныне (&body body)
  `(let ,@body))

(defmacro составить (&body body)
  `(cons ,@body))

(defmacro перевернуть (&body body)
  `(nreverse ,@body))
ugoday ★★★★★
()
Ответ на: комментарий от aho

ну да, если число вхождений каждого из чисел мало, то эффективность падает; а если пооптимизировать, то строк кода будет несколько больше -_-

dismal_faun ★★
()
Ответ на: комментарий от ugoday

Для неруси поганой:

(defun l2h* (source dest)
  (if (null source) dest
      (let* ((hs (car source))
             (ht (cdr source))
             (hd (caar dest))
             (hdn (cdar dest)))
        (if (eq hs hd)
            (l2h* ht (cons (cons hd (+ 1 hdn)) (cdr dest))) 
            (l2h* ht (cons (cons hs 1) dest))))))

(defun l2h (ss)
  (nreverse (l2h* ss NIL)))

ugoday ★★★★★
()
Ответ на: комментарий от aho

Вот встретится тебе код с комментариями на देवनागरी, а ты даже отомстить не сможешь.

ugoday ★★★★★
()
Ответ на: комментарий от dismal_faun

в общем оптимизировать там особо некуда, если уникальных чисел меньше в 10 раз чем их всего, то скорость сравнимая, если больше, то просасывает на операции взятия квадратного корня (преимущественно)

dismal_faun ★★
()

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

anonymous
()
Ответ на: комментарий от anonymous

В любом случае, мы не сможем сделать трудоемкость меньшей, чем O(k), где k - количество различных чисел в массиве.

Единственный способ ускориться, это детектировать цепочку, длины s за меньшее, чем O(s) время. Если ничего дополнительно не известно, лучшее, что мы можем, это детектировать цепочку, длины s за O(log(s)) время, увеличивающимися шагами.

Так что, если в массиве k цепочек длин s1...sk, то время работы можно оценить как O(log(s1)+...+log(sk)), что очевидно меньше O(s1+...+sk).

Это в теории. На практике нужно проверить, будет ли «эффективный» код эффективнее чем непонятнее)))

anonymous
()
Ответ на: комментарий от anonymous

По скорости, этот метод точно такой же, как и рекурсивный алгоритм, предложенный ранее - «если первый и последний равны...». Зря вы его сразу отвергли, он был действительно быстрый и простой для понимания.

anonymous
()
Ответ на: комментарий от kvitaliy

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

ugoday ★★★★★
()
Ответ на: комментарий от kvitaliy

>еще полюбопытсвую - вот эти англо-русские «переобозначения» как влияют на производительность?

Никак. Это макросы.

dave ★★★★★
()
Ответ на: комментарий от Eddy_Em

Жидо-си извратил твой мозг и нормальный ЯП кажется тебе ужасным? Бедняга.

ugoday ★★★★★
()
Ответ на: комментарий от anonymous

Такой ли быстрый?

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

При более беспорядочном доступе к элементам надежды на это уменьшаются.

anarquista ★★★★★
()
Ответ на: комментарий от dismal_faun

Похоже. Вот, посмотрите, на С. Не проверял еще)))

int count_length_of_chain(int a[], int start_index, int length)
{
    if (start_index == length - 1)
        return 1;

    int start = a[start_index];

    int step = 1;

    int current_index = start_index + step;
    int current = a[current_index];

    while (current == start) {
        step *= 2;
        current_index += step;
        if (current_index > length - 1) {
            current_index = length - 1;
            current = a[current_index];
            break;
        }
        current = a[current_index];
    }

    while (current > start) {
        current_index = current_index - 1;
        current = a[current_index];
    }

    return current_index - start_index + 1;
}

int count_length_of_chain(int a[], int start_index, int length)
{
    if (start_index == length - 1)
        return 1;

    int start = a[start_index];

    int step = 1;

    int current_index = start_index + step;
    int current = a[current_index];

    while (current == start) {
        step *= 2;
        current_index += step;
        if (current_index > length - 1) {
            current_index = length - 1;
            current = a[current_index];
            break;
        }
        current = a[current_index];
    }

    while (current > start) {
        current_index = current_index - 1;
        current = a[current_index];
    }

    return current_index - start_index + 1;
}

int count_length_of_chain(int a[], int start_index, int length)
{
    if (start_index == length - 1)
        return 1;

    int start = a[start_index];

    int step = 1;

    int current_index = start_index + step;
    int current = a[current_index];

    while (current == start) {
        current_index += step;
        if (current_index > length - 1) {
            current_index = length - 1;
            current = a[current_index];
            break;
        }
        current = a[current_index];
    }

    return current_index - start_index + 1;
}

list_of_pairs count_elements_freqs(int a[], int length)
{
    int current_index = 0;
    int current_length;
    int current;

    list_of_pairs result;

    while (current_index < length)
    {
        current = a[current_index];
        current_length = count_length_of_chain(a, current_index, length);

        result->add_pair(current, current_length);

        current_index += current_length;
    }

    return r;
}
anonymous
()
Ответ на: комментарий от anonymous

Привел три варианта процедуры

count_length_of_chain(int *, int)[[/code]] - два быстрых, и один стандартный. Может есть косяки, но зато легко понять, и идея понятна.

anonymous
()
Ответ на: комментарий от anonymous

Первый вариант соответствует логарифму по основанию 2, второй, по идее, логарифму по основанию (1+sqrt(5))/2, но при этом промахи будут поменьше.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.