Re[24]: Хэш-таблица vs. дерево поиска
От: adontz Грузия http://adontz.wordpress.com/
Дата: 26.12.05 11:53
Оценка: :)
Здравствуйте, WolfHound, Вы писали:

WH>Ничего не понял. Что не реально? Хеш посчитать не реально?


Посчитать хеш неупорядоченной коллекцииза O(1) нереально, нужно O(N), причём значение хеш-функции не должно зависеть от порядка аргументов (в голову приходит только xor)
Сравнить две неупорядоченные коллекции за O(N) не реально, нужно O(N*log(N)). Причём сравнение реально пишеться и работает, а вот написать хорошую хеш-фунцию, значение которой не зависит от порядка элементов коллекции это интересная задачка. Xor это бомба замедленного действия. Возможно имеет смысл делить достаточно большое число последовательно на все элементы и что-то делать с результатом и остатками Тут вообще надо подумать.
A journey of a thousand miles must begin with a single step © Lau Tsu
Re[13]: Хэш-таблица vs. дерево поиска
От: vdimas Россия  
Дата: 26.12.05 11:58
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>Для малого количества элементов hash функция не имеет большого значения.


Малое — это сколько?
Re[25]: Хэш-таблица vs. дерево поиска
От: WolfHound  
Дата: 27.12.05 06:33
Оценка:
Здравствуйте, adontz, Вы писали:

A>Посчитать хеш неупорядоченной коллекцииза O(1) нереально, нужно O(N), причём значение хеш-функции не должно зависеть от порядка аргументов

А что посчитать хеш упорядоченой коллекции за O(1) можно?
A>(в голову приходит только xor)
Плохо.
A>Сравнить две неупорядоченные коллекции за O(N) не реально, нужно O(N*log(N)).
Если это хеш таблици с веременем поиска O(1) то еще как реально.
A>Причём сравнение реально пишеться и работает, а вот написать хорошую хеш-фунцию, значение которой не зависит от порядка элементов коллекции это интересная задачка. Xor это бомба замедленного действия. Возможно имеет смысл делить достаточно большое число последовательно на все элементы и что-то делать с результатом и остатками Тут вообще надо подумать.
У меня ни разу не получалось написать совсем плохую хеш функцию.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[14]: Хэш-таблица vs. дерево поиска
От: alexeiz  
Дата: 27.12.05 09:02
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Здравствуйте, alexeiz, Вы писали:


A>>Для малого количества элементов hash функция не имеет большого значения.


V>Малое — это сколько?


Где-то до 100.
Re[15]: Хэш-таблица vs. дерево поиска
От: Mab Россия http://shade.msu.ru/~mab
Дата: 27.12.05 09:34
Оценка: 23 (1) +1
Здравствуйте, alexeiz, Вы писали:

A>Где-то до 100.

stdext::hash_set, видимо, далеко не самая удачная реализация хештаблицы. Если кому-нибудь интересно, вот тесты, накиданные на коленке за 5 минут:
Тестируем 100000 итераций, на каждой примерно 50 случайных вставок и 50 случайных поисков. Во всех случаях компилируем VC++/C# 2005 Release.

std::set                                 1593
stdext::hash_set                         2047

Wintellect.PowerCollections.Set          1328
Wintellect.PowerCollections.OrderedSet   1890

Так, хештаблица в .NET оказывается быстрее дерева в native C++, которое оказывается быстрее дерева в .NET. Кстати, один из вариантов ускорения деревьев в .NET более-менее ясен: использовать бинарный предикат сравнения вместо тернарного.

Исходники:
using System;
using Wintellect.PowerCollections;


delegate void Tester();

class MyRandom
{
    int seed;

    public int Next()
    {
        seed = (int) (seed * 214013L + 2531011L);
        return (seed >> 16) & 0x7fff;
    }
}

class Test
{
    static void InvokeTest(Tester tester, string comment)
    {
        int timer0 = Environment.TickCount;
        tester();
        int timer1 = Environment.TickCount;
        Console.WriteLine("{0,-40} {1}", comment, timer1 - timer0);
    }
        
    const int N_OPS = 100;
    const int N_ITERATIONS = 100000;
    
    static void Main()
    {
        InvokeTest(
            delegate
            {
                MyRandom random = new MyRandom();
                Set<int> s  = new Set<int>();
                for (int i = 0; i < N_ITERATIONS; i++)
                {
                    s.Clear();
                    for (int j = 0 ;j < N_OPS; j++)
                    {
                        if (random.Next() % 2 == 0)
                        {
                            s.Add(random.Next());
                        }
                        else
                        {
                            s.Contains(random.Next());
                        }
                    }
                }
            },
            "Wintellect.PowerCollections.Set");
            
        InvokeTest(
            delegate
            {
                MyRandom random = new MyRandom();
                OrderedSet<int> s  = new OrderedSet<int>();
                for (int i = 0; i < N_ITERATIONS; i++)
                {
                    s.Clear();
                    for (int j = 0 ;j < N_OPS; j++)
                    {
                        if (random.Next() % 2 == 0)
                        {
                            s.Add(random.Next());
                        }
                        else
                        {
                            s.Contains(random.Next());
                        }
                    }
                }
            },
            "Wintellect.PowerCollections.OrderedSet");
    }
}

#include <set>
#include <hash_set>
#include <stdlib.h>
#include <time.h>

class MyRandom
{
    int seed;
    
public:    
    MyRandom()
        : seed(0)
    {
    }
    
    int Next()
    {
        seed = (int) (seed * 214013L + 2531011L);
        return (seed >> 16) & 0x7fff;
    }
};

const int N_OPS = 100;
const int N_ITERATIONS = 100000;


template <class T>
void InvokeTest(const T& tester, char* comment)
{
    int t1 = clock();    
    tester.Run();
    int t2 = clock();    
    int time = t2 - t1;
    printf("%-40s %10d\n", comment, time);
}


template <class S>
class Tester
{
public:
    void Run() const
    {
        S s;
        MyRandom random;
        
        for (int i = 0; i < N_ITERATIONS; i++)
        {
            s.clear();
            for (int j = 0 ;j < N_OPS; j++)
            {
                if (random.Next() % 2 == 0)
                {
                    s.insert(random.Next());
                }
                else
                {
                    s.find(random.Next());
                }
            }
        }
    }
};

int main()
{
    InvokeTest(Tester<std::set<int> >(), "std::set");
    InvokeTest(Tester<stdext::hash_set<int> >(), "stdext::hash_set");
}
Re[20]: Хэш-таблица vs. дерево поиска
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.01.06 14:45
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Кстати, несмортя на то, что вопрос не плохой, стоит сделать акцент на том, что удовлетворение всех вовсе не обязательно. Т.е. для кого-то эти массивы равны, если рассматриваются как множества, а для кого-то нет. Действительно, для некоторых задач предпочтительней map-ы, основанные на отношении порядка. Это никак не противоречит тому, что для других задач отношение порядка по боку.


Ага. И если вернуться к вопросу реализации switch-а, то казалось бы зачем для этого упорядычивание?
... << RSDN@Home 1.2.0 alpha rev. 620>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[19]: Хэш-таблица vs. дерево поиска
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.01.06 14:45
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Дело не в сериализации, а в получении упорядоченного множества элементов коллекции. (наверно adontz имел в виду это). В приведенной ссылке одному богу известно зачем Wolfhound использовал Hashtable. Оно там вовсе не нужно.


Зачем Wolfhound хэш-таблица как раз понятно. А вот зачем нужно упорядычивание для реализации switch-а?
... << RSDN@Home 1.2.0 alpha rev. 620>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[21]: Хэш-таблица vs. дерево поиска
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.01.06 14:45
Оценка:
Здравствуйте, adontz, Вы писали:

A>Никто ни в чём не убедился. Сравнением множеств, а не упорядоченных списков это вполне понятно более сложная вычислительная задача. но не неразрешимая. Прямо сейчас могу написать за O(n*log(n))


То есть ты предлагал сделать switch со скоростными характеристиками порядка O(n*log(n)). Ясно. Тогда вопросов больеш нет.

ЗЫ

Может не нужно уходить в такую глубокую демагогию? Вопрос же вроде примитивный. Для реализации хэш-таблицы нет никакого смысла использовать упорядоченние. Это не применимо во многих случаях и работает медленее чем хэш-таблица. О чем тогда разговор? Неужели имеет смысл упираться в столь очевидные вопросы?
... << RSDN@Home 1.2.0 alpha rev. 620>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[17]: Хэш-таблица vs. дерево поиска
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.01.06 14:45
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Если твой StateSet рассматривать как упорядоченное множество State-ов, то отношение порядка для него строится более чем легко при существовании отношения порядка для самих State-ов.


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


Здорово! И по ходу преобразования НКА в ДКА мы много раз будет удалять и добавлять состояния. При этом будут меняться характеристики множеств. Они то будут "больше" других, то "меньше". Для решаемой задачи — это не имеет никакого значения. Но мы, чисто от вредности, будет пересчитаывать все внутренние структуры.

А смысл? Хэш-таблица решает задачу без побочных эффектов и к тмоу же далате это быстрее чем другие методы.
... << RSDN@Home 1.2.0 alpha rev. 620>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[11]: Хэш-таблица vs. дерево поиска
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.01.06 14:45
Оценка:
Здравствуйте, alexeiz, Вы писали:

WH>>Почему такой стериотип что switch должен быть построен на дереве, а не на хеш таблице?


A>Дерево работает быстрее, чем hash таблица, для малого количества элементов. Я проверял на std::set и stdext::hash_set из библиотеки VC8. Для .NET можно тоже проверить, знать бы только, где есть хорошая реализация контейнера, построеного на деревьях.


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

Хэш-таблица имеет константное время доступа при хорошей хэш-функции. Для поиска элементов требуется только лишь взять хэш вычеслить по нему слот хэш-таблицы и извлечь из него значение. Даже сравнение не нужно. А в случае коллизий и возможности сравнить элементы на больше/меньше коллизии можно и отсортировать. Тогда уж дерево не соможет быть быстрее ни в каком случае. Даже в случае клиничевки хреновой хэш-функции.
... << RSDN@Home 1.2.0 alpha rev. 620>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[15]: Хэш-таблица vs. дерево поиска
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.01.06 14:45
Оценка:
Здравствуйте, Mab, Вы писали:

Mab>На приведенный пример есть одно возражение: число корзин хеш-таблицы -- всегда простое число, так что 100 там не может быть даже теоретически.


Это эвристика котору не обязательно соблюдать. Так что "всегда" в данном случае говорить неуместно.
... << RSDN@Home 1.2.0 alpha rev. 620>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[17]: Хэш-таблица vs. дерево поиска
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.01.06 14:45
Оценка:
Здравствуйте, Mab, Вы писали:

Mab>Конечно, странно ожидать от входных данных истинно равномерного распределения. Насчет 'наполовину' -- откуда это взялось, я не понял.


А откуда ты взял "наполовину"? Эксперементально доказано, что обычно эффективная работа хэш-таблиц начинается с момента когда количество слотов в 1.3 раза больше чем элементов подлежащих хранению. В два раз — это еще лучше, конечно. Но в 3 еще. И пока хэш-таблица попадает в кэш, разницы особо не будет.
... << RSDN@Home 1.2.0 alpha rev. 620>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[16]: Хэш-таблица vs. дерево поиска
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.01.06 14:45
Оценка: 18 (1)
Здравствуйте, Mab, Вы писали:

Кстати, тиками измерять время не здорово. Особнно не здорово из-за того, что они иногда врут. По крайней мере во втором дотнете лучше использовать Stopwatch.
... << RSDN@Home 1.2.0 alpha rev. 620>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[13]: Хэш-таблица vs. дерево поиска
От: Pzz Россия https://github.com/alexpevzner
Дата: 02.01.06 15:22
Оценка: +1
adontz wrote:
>
> Хеш ключа это индекс в хеш-таблице (обычный массив), значения которой
> это списки пар (ключ, значение). А что у нас возвращает замечательная
> функция GetHashCode()? А она у нас возвращает int, 32битное число.
> Размер массива который бы индексировался таким числом просто огромен,
> значительно превышает не только средний, но и максимальный объём памяти
> (который обычно 4Гб, но даже в 64 это всё не влезет).

Ну, вообще-то говоря, если все case'ы — константы, известные во время
компиляции, то компилятор может сам сгенерировать hash-функцию, которая
никогда не будет давать коллизий, и будет при этом использовать
небольшую таблицу. В таком случае hash-поиск будет очень эффективен.
Posted via RSDN NNTP Server 2.0
Re[18]: Хэш-таблица vs. дерево поиска
От: Mab Россия http://shade.msu.ru/~mab
Дата: 02.01.06 15:27
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>А откуда ты взял "наполовину"?

Ну так adontz писал:

Выходит проектировали сразу для плохой и хеш таблица заполненая меньше чем наполовину это норма?

Re[17]: Хэш-таблица vs. дерево поиска
От: Mab Россия http://shade.msu.ru/~mab
Дата: 02.01.06 15:29
Оценка:
Здравствуйте, VladD2, Вы писали:

VDПо крайней мере во втором дотнете лучше использовать Stopwatch.
Здорово... не знал про него.
Re[16]: Хэш-таблица vs. дерево поиска
От: Mab Россия http://shade.msu.ru/~mab
Дата: 02.01.06 15:41
Оценка:
Здравствуйте, VladD2, Вы писали:

Mab>>На приведенный пример есть одно возражение: число корзин хеш-таблицы -- всегда простое число, так что 100 там не может быть даже теоретически.


VD>Это эвристика котору не обязательно соблюдать.

ОК, согласен, что реализовать абы какую хештаблицу можно хоть на 2^16 корзинах.

Я имел в виду (и, очевидно, выразил эту мысль плохо), что при использовании двойного хеширования (в частности, оно использовано в .NET Framework) размер обязан быть простым числом, т.к. при составном числе корзин m не все ненулеые вычеты оказываются порождающими mod m. Т.е. при данном конкретном способе реализации это не эвристика, а необходимое требование.
Re[22]: Хэш-таблица vs. дерево поиска
От: adontz Грузия http://adontz.wordpress.com/
Дата: 02.01.06 15:54
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Может не нужно уходить в такую глубокую демагогию?


Да-да, действительно. Я пошёл пить чай и жрать конфеты.
A journey of a thousand miles must begin with a single step © Lau Tsu
Re[12]: Хэш-таблица vs. дерево поиска
От: alexeiz  
Дата: 02.01.06 20:28
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, alexeiz, Вы писали:


WH>>>Почему такой стериотип что switch должен быть построен на дереве, а не на хеш таблице?


A>>Дерево работает быстрее, чем hash таблица, для малого количества элементов. Я проверял на std::set и stdext::hash_set из библиотеки VC8. Для .NET можно тоже проверить, знать бы только, где есть хорошая реализация контейнера, построеного на деревьях.


VD>Что ты проверял? Ну, это уже просто выходит за границы разумного.


За границы разумного выходят твои книжные знания. Ассимптотичное поведение не имеет ни малейшего значения для малых N.

VD>Блин, читайте классику и не смотрите на результаты эксперементов производимых на базе откровенно лажевых реализаций контейнеров.


VD>Хэш-таблица имеет константное время доступа при хорошей хэш-функции. Для поиска элементов требуется только лишь взять хэш вычеслить по нему слот хэш-таблицы и извлечь из него значение. Даже сравнение не нужно. А в случае коллизий и возможности сравнить элементы на больше/меньше коллизии можно и отсортировать. Тогда уж дерево не соможет быть быстрее ни в каком случае. Даже в случае клиничевки хреновой хэш-функции.


Тебе объяснить на пальцах?

Для количества элементов в контейнере равное 1 дерево будет быстрее хэш-таблицы, это очевидно. Для достаточно большого количества элементов хэш-таблица с хорошей хэш-функцией будет быстрее дерева. Значит, есть такое количество элементов, вплоть до которого дерево будет быстрее чем хэш-таблица.
Re[13]: Хэш-таблица vs. дерево поиска
От: Mab Россия http://shade.msu.ru/~mab
Дата: 02.01.06 20:35
Оценка:
Здравствуйте, alexeiz, Вы писали:
A>Для количества элементов в контейнере равное 1 дерево будет быстрее хэш-таблицы, это очевидно. Для достаточно большого количества элементов хэш-таблица с хорошей хэш-функцией будет быстрее дерева. Значит, есть такое количество элементов, вплоть до которого дерево будет быстрее чем хэш-таблица.

Ты ошибаешься вот в чем: в отличие от дерева, у хештаблицы есть дополнительный параметр -- коэффициент заполнения, который напрямую влияет на скорость. Если его сделать достаточно большим и считать, что хешфункция хорошая, то время доступа будет O(1). Так что такое лобовое сравнение с деревом не годится. Засчет дополнительного расхода по памяти хештаблица может успешно обогнать дерево на любых размерах. Вопрос только в том, устраивает ли тебя такой tradeoff.

Это, кстати, и показывают тесты, которые я привел ранее -- хештаблица .NET обгоняет std::map на 50 элементах.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.