Поиск:

Ответ в темуСоздание новой темы Создание опроса
> МОДА 
V
    Опции темы
Golden Hands
Дата 16.5.2006, 13:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Золотой
****


Профиль
Группа: Участник Клуба
Сообщений: 2023
Регистрация: 23.1.2005
Где: Екатеринбург

Репутация: нет
Всего: 83



SoWa, начну с реализации твоей идеи. 


--------------------
Мы обречены... но только на победу!
Настанет день, и мы построим новый дом.
Внесем в него тепло, что сохранить сумели,
И воскресим все то, что в нас когда-то умерло... © Тень Света
PM MAIL ICQ   Вверх
maxim1000
Дата 16.5.2006, 13:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 3334
Регистрация: 11.1.2003
Где: Киев

Репутация: 33
Всего: 110



Цитата(Mayk @  16.5.2006,  10:37 Найти цитируемый пост)
Есть бинарное дерево поиска.


Цитата(nostromo @  16.5.2006,  10:53 Найти цитируемый пост)
Поиск в бинарном дереве как раз и имеет сложность log(n)


я бы уточнил: поиск в сбалансированном бинарном дереве пропорционален log(n)

в худшем случае он пропорционален n, так что придётся тратить время на балансировку
...
впрочем, и быстрая сортировка в худшем случае пропорциональна n^2 smile

если есть достаточно памяти (ещё столько ж, сколько занимает массив), то лучше сортировка слиянием - она гарантированно занимает n*log n... 


--------------------
qqq
PM WWW   Вверх
Golden Hands
Дата 16.5.2006, 14:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Золотой
****


Профиль
Группа: Участник Клуба
Сообщений: 2023
Регистрация: 23.1.2005
Где: Екатеринбург

Репутация: нет
Всего: 83



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

Код

g:=1;
for i:=1 to High(element) do
  Begin
    count[i]:=0;
    if g=i then
      Begin
        t:=element[g];
        for k:=g to High(element) do
          if t:=element[k] then count[i]:=count[i]+1
          else
            Begin
              g:=k;
              break;
            End; 
      End;
    <over>
  End;
 

Временные затраты очень малы. Что и следовало...  smile  

Всех благодарю за участие! 

Это сообщение отредактировал(а) Golden Hands - 16.5.2006, 14:51


--------------------
Мы обречены... но только на победу!
Настанет день, и мы построим новый дом.
Внесем в него тепло, что сохранить сумели,
И воскресим все то, что в нас когда-то умерло... © Тень Света
PM MAIL ICQ   Вверх
sergejzr
Дата 16.5.2006, 14:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Un salsero
Group Icon


Профиль
Группа: Админ
Сообщений: 13285
Регистрация: 10.2.2004
Где: Германия г .Ганновер

Репутация: 4
Всего: 360



С вариантом nostromo, будет значительно быстрее. 


--------------------
PM WWW IM ICQ Skype GTalk Jabber AOL YIM MSN   Вверх
Mayk
Дата 17.5.2006, 06:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


^аВаТаР^ сообщение>>
****


Профиль
Группа: Участник
Сообщений: 2616
Регистрация: 22.5.2005
Где: за границей разум а

Репутация: 2
Всего: 134



Цитата(nostromo @  16.5.2006,  15:53 Найти цитируемый пост)
Поиск в бинарном дереве как раз и имеет сложность log(n)  


Цитата(nostromo @  16.5.2006,  15:53 Найти цитируемый пост)
в лучшем случае на это понадобится log(n) - это если хранить в упорядоченном массиве... только тогда добавление будет дольше...  

Добавление в отсортированный массив занимает в худшем случае линейное время.
(дан массив (2,3,4,5). Для того чтобы добавить в него 1 понадобится скопировать ВЕСЬ массив).
В случае сбалансированного(как справедливо отметили выше) бинарного дерева добавление возможно за log(n) 
  

Это сообщение отредактировал(а) Mayk - 17.5.2006, 06:21


--------------------
 Здесь был кролик. Но его убили.
Человеки < кроликов, йа считаю.
PM MAIL WWW ICQ   Вверх
esperant0
Дата 17.5.2006, 07:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 714
Регистрация: 20.5.2005

Репутация: 4
Всего: 14



Цитата(nostromo @ 16.5.2006,  09:10)
Можно за один проход (ну почти ;) ).
Постоянно храним и обновляем список встреченных значений, их текущее количество (список частот), а также индекс в списке элемента, который встретился максимальное число раз. 
При обработке очередного элемента обновляем соответствующую ячейку списка частот и проверяем, не побит ли рекорд. 

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

1) Во-первых, ваше "что алгоритм работает за один проход только в случае, когда"   .... неверно


2) Во-вторых в общем случае ваш алгоритм работает за х*лог х времени.


с ув 


--------------------
 
 Student->Teacher Assistant ->Research assistant->Microsoft Software Development Engineer 

Пользователь получил наказание за то, что проигнорировал замечание которое было написано модератором  а затем стерто и которое он - пользователь не мог видеть. 
PM MAIL   Вверх
esperant0
Дата 17.5.2006, 07:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 714
Регистрация: 20.5.2005

Репутация: 4
Всего: 14



Цитата(nostromo @ 16.5.2006,  11:26)
Цитата

в лучшем случае на это понадобится log(n) - это если хранить в упорядоченном массиве... только тогда добавление будет дольше...


Нет, вычисляем хэш от очередного числа и находим его индекс. Никакого log(n).

конечно же. нет. 


--------------------
 
 Student->Teacher Assistant ->Research assistant->Microsoft Software Development Engineer 

Пользователь получил наказание за то, что проигнорировал замечание которое было написано модератором  а затем стерто и которое он - пользователь не мог видеть. 
PM MAIL   Вверх
nostromo
Дата 17.5.2006, 14:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 194
Регистрация: 23.3.2006

Репутация: 5
Всего: 10



Сейчас, сейчас...

Критерием истины, как известно, является практика, поэтому приступим.

Пусть входными элементами будут целые числа, а в качестве хэш функции
возьмем остаток от деления на фиксированное число (bufSize).
Список частот (currFreq) будем хранить в массиве размера bufSize.
На случай коллизий, в каждом элементе currFreq будем хранить список пар
(<число> @ <частота>).

Программу напишем на Smalltlak (VisualWorks). В этой простой задаче обойдемся стандартной библиотекой и новых классов создавать не будем. 

Собственно программа:
Код

bufSize := 10000.
hashFunc := [:x | (x \\ bufSize) + 1].  

main := 
[:input |  
  res := 0 @ 0.

  currFreq := Array new: bufSize.
  currFreq doWithIndex: [:x :i | currFreq at: i put: List new].

  input do: [:x | 
    | ind list ind1 |
    ind := hashFunc value: x.
    list := currFreq at: ind.
    ind1 := list findFirst: [:p | p x = x].
    ind1 > 0 ifTrue: [ | nn pair | pair := list at: ind1. 
          nn := pair y + 1. pair y: nn. 
          (nn > res y) ifTrue: [res x: pair x. res y: nn. ]]
        ifFalse: [ list add: x @ 1]].
  res.
].


Проверяем работу:
Код

input := #( 5 3 6 4 5 8 7 9 6 6 7 6 3 2 1 3 5 6 7 8 9 9).
main  value: input 
Результат:  6@5
Действительно, число 6 встречается 5 раз, и это максимум.


Проверяем зависимость вермени работы от размера входного массива,
в котором записаны случайные числа.
Сначала пусть случайные числа будут в диапазоне от 1 до 100 (много коллизий)
Код

rndGen := Random new.
rnd := [(rndGen next * 100) truncated].

counts := #(2000 4000 8000 16000 32000 64000 128000 256000  512000).
res := counts collect: [:nn | 
input := (1 to: nn) collect: [:i | rnd value].
nn1 := 5. "количество итераций для осреднения"
times := (1 to: nn1) collect: [:i | Core.Time millisecondsToRun: [main  value: input]]. 
r1 := (times inject: 0 into: [:r :n | r + n]) / nn1. "среднее время"
r1 rounded.].
В переменной res:
#(8 12 15 25 18 25 39 64 120)

--- очевидно, линейный рост времени исполнения, накокого n*log(n).

Теперь случай, когда случайные числа в диапазоне от 1 до 10^7 (мало коллизий):
Код

rndGen := Random new.
rnd := [(rndGen next * 1e7) truncated].

counts := #(2000 4000 8000 16000 32000 64000 128000 256000  512000).
res := counts collect: [:nn | 
input := (1 to: nn) collect: [:i | rnd value].
nn1 := 5. "количество итераций для осреднения"
times := (1 to: nn1) collect: [:i | Core.Time millisecondsToRun: [main  value: input]]. 
r1 := (times inject: 0 into: [:r :n | r + n]) / nn1. "среднее время"
r1 rounded.].
В переменной res:
 #(9 13 15 15 27 45 116 304 997 3613)

--- в этом случае требуется заметно больше памяти (больше элементов попадает в currFreq, плюс сами числа требуют больше памяти --- Smalltalk автоматически перобразует целые числа, в первом случае они влазили в Smallint (два байта)), 
поэтому линейная асимптотика для больших значений немного испорчена сборщиком мусора. 
В случае асимптотики n*log(n) время на каждом шаге должно было бы
вырастать в 4 раза.

Добавлено @ 14:55 
Небольшая поправка, в последнем тесте
counts := #(1000 2000 4000 8000 16000 32000 64000 128000 256000 512000).
(Не оттуда скопировал.) 
--------------------
На пыльных тропинках далеких планет останутся наши следы.
PM MAIL   Вверх
sergejzr
Дата 17.5.2006, 15:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Un salsero
Group Icon


Профиль
Группа: Админ
Сообщений: 13285
Регистрация: 10.2.2004
Где: Германия г .Ганновер

Репутация: 4
Всего: 360



nostromo, отлично, только надо учесть негативные числа в хэш-функции (то есть брать |х| ) 


--------------------
PM WWW IM ICQ Skype GTalk Jabber AOL YIM MSN   Вверх
nostromo
Дата 17.5.2006, 15:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 194
Регистрация: 23.3.2006

Репутация: 5
Всего: 10



Цитата
 В случае асимптотики n*log(n) время на каждом шаге должно было бы
вырастать в 4 раза. 

Виноват, это совсем не так. Зависимость сложнее:
если n пробегает ряд
(2 4 8 16 32 64 128 256  512),
то n*log(n) пробегает ряд: 
(2 8 24 64 160 384 896 2048 4608).

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

Добавлено @ 15:48 
sergej.z, спасибо.  
--------------------
На пыльных тропинках далеких планет останутся наши следы.
PM MAIL   Вверх
esperant0
Дата 17.5.2006, 22:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 714
Регистрация: 20.5.2005

Репутация: 4
Всего: 14



Цитата(nostromo @ 17.5.2006,  14:51)
Сейчас, сейчас...

Критерием истины, как известно, является практика, поэтому приступим.
 

Я конечно еще раз извенюсь.

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

А ваше численные примеры, лишь смущают не ведующих. А на самом деле профанация чистой воды.


с уважением 


--------------------
 
 Student->Teacher Assistant ->Research assistant->Microsoft Software Development Engineer 

Пользователь получил наказание за то, что проигнорировал замечание которое было написано модератором  а затем стерто и которое он - пользователь не мог видеть. 
PM MAIL   Вверх
maxim1000
Дата 17.5.2006, 23:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 3334
Регистрация: 11.1.2003
Где: Киев

Репутация: 33
Всего: 110



сложность поиска по хешу - вопрос интересный
это как раз тот случай, когда целесообразность анализа "при достаточно больших n" можно поставить под сомнение

если исследовать поведение хеша при n->oo, то он принципиально ничем не отличается от того же бинарного дерева (только у узлов там не два, а куча потомков, да и уже на втором уровне деревянная структура может не сохраняться), а значит поиск по хешу ("хорошему" хешу, что эквивалентно сбалансированности дерева) будет занимать log n (да и то, это если на втором уровне не делать чего-то типа списка/массива)

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

Это сообщение отредактировал(а) maxim1000 - 17.5.2006, 23:43


--------------------
qqq
PM WWW   Вверх
nostromo
Дата 18.5.2006, 09:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 194
Регистрация: 23.3.2006

Репутация: 5
Всего: 10



Уважаемый esperant0, по-видимому, наши разногласия связаны с различным пониманием постановки задачи, что верно заметил maxim1000.

Еще раз попробую внести ясность.

1. На вход алгоритма поступет массив M из N элементов.
2. Допущения:
    1.1. Оперативной памяти всегда достаточно, сборкой мусора, особенностями операционной системы и другими внешними факторами пренебрегаем.
    1.2. Всегда есть возможность за фиксированное время в зависимости от N настроить парметры хэш-функции так, чтобы она выдавала значения от 1 до некоторого N1 (также зависящего от N) с пренебрежимо малым числом коллизий.
    1.3. Выделение памяти под вспомогательный N1-элементный список частот занимает фиксированное время, не зависящее от N1 (или зависящее пренебрежимо слабо).
    1.4. Доступ к элементу массива (или списка) по его индексу всегда занимает фиксированное время.
3. Алгоритм.
    3.1. Инициализация. Выбирается хэш функция, со свойствами, описанными в 1.2 и создается список частот M1 размера N1. (В списке частот хранится текущее количество встреч элементов.) Инициализируются переменные для значения элемента, который встречается максимальное число раз и частота его встречи (нулем).
    3.2. Последовательно в цикле перебираются элементы входного массива M 
и для каждого из них выполняются следующие действия.
        3.2.1. С помощью хэш функции вычисляется индекс элемента в списке частот.
        3.2.1. По индексу находится элемент списка частот и инкрементируется значение текущего числа встреч элемента. (Выполнение этого пункта занимает фиксированное время --- это следует из предположения о пренебрежимо малом числе коллизий хэш функции.)
        3.2.3. Проверяется, не превосходит ли число встреч текущего элемента рекордного значения и, если превосходит, рекордное значение обновляется.
4. Очевидно, что при указанных допущениях, от размера входного массива зависит только число итераций цикла --- оно совпадает с N, значит, сложность алгоритма --- линейная.
 
--------------------
На пыльных тропинках далеких планет останутся наши следы.
PM MAIL   Вверх
esperant0
Дата 18.5.2006, 20:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 714
Регистрация: 20.5.2005

Репутация: 4
Всего: 14



Цитата(nostromo @ 18.5.2006,  09:12)
Уважаемый esperant0, по-видимому, наши разногласия связаны с различным пониманием постановки задачи, что верно заметил maxim1000.

Еще раз попробую внести ясность.

1. На вход алгоритма поступет массив M из N элементов.
2. Допущения:
    1.1. Оперативной памяти всегда достаточно, сборкой мусора, особенностями операционной системы и другими внешними факторами пренебрегаем.
    1.2. Всегда есть возможность за фиксированное время в зависимости от N настроить парметры хэш-функции так, чтобы она выдавала значения от 1 до некоторого N1 (также зависящего от N) с пренебрежимо малым числом коллизий.
    1.3. Выделение памяти под вспомогательный N1-элементный список частот занимает фиксированное время, не зависящее от N1 (или зависящее пренебрежимо слабо).
    1.4. Доступ к элементу массива (или списка) по его индексу всегда занимает фиксированное время.
3. Алгоритм.
    3.1. Инициализация. Выбирается хэш функция, со свойствами, описанными в 1.2 и создается список частот M1 размера N1. (В списке частот хранится текущее количество встреч элементов.) Инициализируются переменные для значения элемента, который встречается максимальное число раз и частота его встречи (нулем).
    3.2. Последовательно в цикле перебираются элементы входного массива M 
и для каждого из них выполняются следующие действия.
        3.2.1. С помощью хэш функции вычисляется индекс элемента в списке частот.
        3.2.1. По индексу находится элемент списка частот и инкрементируется значение текущего числа встреч элемента. (Выполнение этого пункта занимает фиксированное время --- это следует из предположения о пренебрежимо малом числе коллизий хэш функции.)
        3.2.3. Проверяется, не превосходит ли число встреч текущего элемента рекордного значения и, если превосходит, рекордное значение обновляется.
4. Очевидно, что при указанных допущениях, от размера входного массива зависит только число итераций цикла --- оно совпадает с N, значит, сложность алгоритма --- линейная.

1.2 не реабельно. то есть не выполнимо в общем случае 


--------------------
 
 Student->Teacher Assistant ->Research assistant->Microsoft Software Development Engineer 

Пользователь получил наказание за то, что проигнорировал замечание которое было написано модератором  а затем стерто и которое он - пользователь не мог видеть. 
PM MAIL   Вверх
nostromo
Дата 19.5.2006, 08:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 194
Регистрация: 23.3.2006

Репутация: 5
Всего: 10



Цитата

1.2 не реабельно. то есть не выполнимо в общем случае

Да ну? А что такое общий случай?

С точки зрения практики, этот пункт один из самых легко достижимых.
Могу предложить универсальный способ для любых объектов.
Хэш функция выглядит следующим образом:
входной объект, сериализуется в строку, вычисляеется от нее MD5-хэш,
он, в свою очередь, берется по модулю параметра K. Все.
Настройка хэш функции, осуществляемая в секции инициализации алгоритма, заключается в установке значения K, например, равным числу элементов входного массива. 
Здесь скорее проблема придумать хороший контрпример.

Предложенный алгоритм поиска моды имеет линейную сложность (от размера входного массива) и в теории и на практике (пока хватает оперативной памяти), а Вы, кажется, просто не хотите это признать.

Добавлено @ 09:02 
Если подходить совсем строго, с теоретической точки зрения для любого произвольного входного массива, о котором вообще ничего не известно, кроме числа элементов, действительно нельзя гарантированно предложить хэш функцию с малым число коллизий. Однако на практике, это почти всегда возможно, плюс, с самого начала я говорил, что алгоритм имеет линейную сложность при условии существования "хорошей" хэш-функции.
 
--------------------
На пыльных тропинках далеких планет останутся наши следы.
PM MAIL   Вверх
Страницы: (3) Все 1 [2] 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Алгоритмы"

maxim1000

Форум "Алгоритмы" предназначен для обсуждения вопросов, связанных только с алгоритмами и структурами данных, без привязки к конкретному языку программирования и/или программному продукту.


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, maxim1000.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Алгоритмы | Следующая тема »


 




[ Время генерации скрипта: 0.0636 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.