Сведения о вопросе

Oleksandrop

05:23, 16th August, 2020

Теги

Как бы вы реализовали хэш-таблицу в языке x?

Просмотров: 513   Ответов: 9

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

Редактировать :

Почему бы просто не использовать встроенные функции hash в вашем конкретном языке?

Потому что мы должны знать, как работают таблицы hash и уметь их реализовывать. Это может показаться не очень важной темой, но знание того, как работает одна из наиболее часто используемых структур данных, кажется мне очень важным. Если это должно стать Википедией программирования, то вот некоторые из типов вопросов, за которыми я сюда приду. Я не ищу книгу CS, которая будет написана здесь. Я мог бы взять с полки вступление к алгоритмам и прочитать главу о таблицах hash и получить такую информацию. Более конкретно, то, что я ищу, - это примеры кода . Не только для меня в частности, но и для других, кто, возможно, однажды будет искать подобную информацию и наткнется на эту страницу.

Если бы вы должны были их реализовать и не могли использовать встроенные функции, как бы вы это сделали?

Вам не нужно ставить код здесь. Положите его в пастебин и просто соедините его.



  Сведения об ответе

PIRLO

20:40, 27th August, 2020

Таблица hash структура данных, которая позволяет осуществлять поиск элементов в постоянном времени. Он работает путем хэширования значения и преобразования этого значения в смещение в массиве. Концепция таблицы hash довольно проста для понимания, но ее реализация явно сложнее. Я не вставляю сюда всю таблицу hash, но вот некоторые фрагменты таблицы hash, которую я сделал в C несколько недель назад...

Одна из основ создания таблицы hash - это наличие хорошей функции hash. Я использовал функцию djb2 hash в моей таблице hash:

int ComputeHash(char* key)
{
    int hash = 5381;
    while (*key)
    hash = ((hash << 5) + hash) + *(key++);
    return hash % hashTable.totalBuckets;
}

Затем идет сам фактический код для создания и управления ведрами в таблице

typedef struct HashTable{
    HashTable* nextEntry;
    char*      key;
    char*      value;
}HashBucket;

typedef struct HashTableEntry{
    int totalBuckets;       // Total number of buckets allocated for the hash table
    HashTable** hashBucketArray; // Pointer to array of buckets
}HashTableEntry;
HashTableEntry hashTable;

bool InitHashTable(int totalBuckets)
{
    if(totalBuckets > 0)
    {
        hashTable.totalBuckets = totalBuckets;
        hashTable.hashBucketArray = (HashTable**)malloc(totalBuckets * sizeof(HashTable));
        if(hashTable.hashBucketArray != NULL)
        {
            memset(hashTable.hashBucketArray, 0, sizeof(HashTable) * totalBuckets);
            return true;
        }
    }
    return false;
}

bool AddNode(char* key, char* value)
{
    int offset = ComputeHash(key);
    if(hashTable.hashBucketArray[offset] == NULL)
    {
        hashTable.hashBucketArray[offset] = NewNode(key, value);
        if(hashTable.hashBucketArray[offset] != NULL)
            return true;
    }

    else
    {
        if(AppendLinkedNode(hashTable.hashBucketArray[offset], key, value) != NULL)
            return true;
    }
    return false;
}

HashTable* NewNode(char* key, char* value)
{
    HashTable* tmpNode = (HashTable*)malloc(sizeof(HashTable));
    if(tmpNode != NULL)
    {
        tmpNode->nextEntry = NULL;
        tmpNode->key   = (char*)malloc(strlen(key));
        tmpNode->value = (char*)malloc(strlen(value));

        strcpy(tmpNode->key, key);
        strcpy(tmpNode->value, value);
    }
    return tmpNode;
}

AppendLinkedNode находит последний узел в связанном списке и добавляет к нему новый узел.

Код будет использоваться следующим образом:

if(InitHashTable(100) == false) return -1;
AddNode("10", "TEN");

Найти узел очень просто, так как:

HashTable* FindNode(char* key)
{
    int offset = ComputeHash(key);
    HashTable* tmpNode = hashTable.hashBucketArray[offset];
    while(tmpNode != NULL)
    {
        if(strcmp(tmpNode->key, key) == 0)
            return tmpNode;
        tmpNode = tmpNode->nextEntry;
    }
    return NULL;
}

И используется следующим образом:

char* value = FindNode("10");


  Сведения об ответе

appple

23:55, 16th August, 2020

A Java реализация в < 60 LoC

import java.util.ArrayList;
import java.util.List;
import java.util.Random;


public class HashTable {

    class KeyValuePair {

        Object key;

        Object value;

        public KeyValuePair(Object key, Object value) {
            this.key = key;
            this.value = value;
        }
    }

    private Object[] values;

    private int capacity;

    public HashTable(int capacity) {
        values = new Object[capacity];
        this.capacity = capacity;
    }

    private int hash(Object key) {
        return Math.abs(key.hashCode()) % capacity;
    }

    public void add(Object key, Object value) throws IllegalArgumentException {

        if (key == null || value == null)
            throw new IllegalArgumentException("key or value is null");

        int index = hash(key);

        List<KeyValuePair> list;
        if (values[index] == null) {
            list = new ArrayList<KeyValuePair>();
            values[index] = list;

        } else {
            // collision
            list = (List<KeyValuePair>) values[index];
        }

        list.add(new KeyValuePair(key, value));
    }

    public Object get(Object key) {
        List<KeyValuePair> list = (List<KeyValuePair>) values[hash(key)];
        if (list == null) {
            return null;
        }
        for (KeyValuePair kvp : list) {
            if (kvp.key.equals(key)) {
                return kvp.value;
            }
        }
        return null;
    }

    /**
     * Test
     */
    public static void main(String[] args) {

        HashTable ht = new HashTable(100);

        for (int i = 1; i <= 1000; i++) {
            ht.add("key" + i, "value" + i);
        }

        Random random = new Random();
        for (int i = 1; i <= 10; i++) {
            String key = "key" + random.nextInt(1000);
            System.out.println("ht.get(\"" + key + "\") = " + ht.get(key));
        }   
    }
}


  Сведения об ответе

darknet

14:22, 4th August, 2020

A HashTable-это действительно простая концепция: это массив, в который помещаются пары ключей и значений (как в ассоциативный массив) по следующей схеме:

Функция hash хэширует ключ к (надеюсь) неиспользуемому индексу в массиве. затем значение помещается в массив по этому конкретному индексу.

Извлечение данных легко, так как индекс в массиве может быть вычислен с помощью функции hash, таким образом, поиск вверх является ~ O(1).

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

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


  Сведения об ответе

SKY

10:17, 11th August, 2020

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


  Сведения об ответе

LAST

18:07, 11th August, 2020

Вот мой код для таблицы Hash, реализованный в Java. Страдает от незначительного сбоя-поля ключа и значения не совпадают. Возможно, в будущем это будет изменено.

public class HashTable
{
    private LinkedList[] hashArr=new LinkedList[128];
    public static int HFunc(int key)
    {
        return key%128;
    }


    public boolean Put(Val V)
    {

        int hashval = HFunc(V.getKey());
        LinkedNode ln = new LinkedNode(V,null);
        hashArr[hashval].Insert(ln);
        System.out.println("Inserted!");
        return true;            
    }

    public boolean Find(Val V)
    {
        int hashval = HFunc(V.getKey());
        if (hashArr[hashval].getInitial()!=null && hashArr[hashval].search(V)==true)
        {
            System.out.println("Found!!");
            return true;
        }
        else
        {
            System.out.println("Not Found!!");
            return false;
        }

    }
    public boolean delete(Val v)
    {
        int hashval = HFunc(v.getKey());
        if (hashArr[hashval].getInitial()!=null && hashArr[hashval].delete(v)==true)
        {
            System.out.println("Deleted!!");
            return true;
        }
        else 
        {
            System.out.println("Could not be found. How can it be deleted?");
            return false;
        }
    }

    public HashTable()
    {
        for(int i=0; i<hashArr.length;i++)
            hashArr[i]=new LinkedList();
    }

}

class Val
{
    private int key;
    private int val;
    public int getKey()
    {
        return key;
    }
    public void setKey(int k)
    {
        this.key=k;
    }
    public int getVal()
    {
        return val;
    }
    public void setVal(int v)
    {
        this.val=v;
    }
    public Val(int key,int value)
    {
        this.key=key;
        this.val=value;
    }
    public boolean equals(Val v1)
    {
        if (v1.getVal()==this.val)
        {
            //System.out.println("hello im here");
            return true;
        }
        else 
            return false;
    }
}

class LinkedNode
{
    private LinkedNode next;
    private Val obj;
    public LinkedNode(Val v,LinkedNode next)
    {
        this.obj=v;
        this.next=next;
    }
    public LinkedNode()
    {
        this.obj=null;
        this.next=null;
    }
    public Val getObj()
    {
        return this.obj;    
    }
    public void setNext(LinkedNode ln)
    {
        this.next = ln;
    }

    public LinkedNode getNext()
    {
        return this.next;
    }
    public boolean equals(LinkedNode ln1, LinkedNode ln2)
    {
        if (ln1.getObj().equals(ln2.getObj()))
        {
            return true;
        }
        else 
            return false;

    }

}

class LinkedList
{
    private LinkedNode initial;
    public LinkedList()
    {
        this.initial=null;
    }
    public LinkedList(LinkedNode initial)
    {
        this.initial = initial;
    }
    public LinkedNode getInitial()
    {
        return this.initial;
    }
    public void Insert(LinkedNode ln)
    {
        LinkedNode temp = this.initial;
        this.initial = ln;
        ln.setNext(temp);
    }
    public boolean search(Val v)
    {
        if (this.initial==null)
            return false;
        else 
        {
            LinkedNode temp = this.initial;
            while (temp!=null)
            {
                //System.out.println("encountered one!");
                if (temp.getObj().equals(v))
                    return true;
                else 
                    temp=temp.getNext();
            }
            return false;
        }

    }
    public boolean delete(Val v)
    {
        if (this.initial==null)
            return false;
        else 
        {
            LinkedNode prev = this.initial;
            if (prev.getObj().equals(v))
            {
                this.initial = null;
                return true;
            }
            else
            {
                LinkedNode temp = this.initial.getNext();
            while (temp!=null)
            {
                if (temp.getObj().equals(v))
                {
                    prev.setNext(temp.getNext());
                    return true;
                }
                else
                {
                    prev=temp;
                    temp=temp.getNext();
                }
            }
            return false;
            }
        }
    }
}


  Сведения об ответе

Chhiki

18:34, 29th August, 2020

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

> let hashtbl xs =
    let spine = [|for _ in xs -> ResizeArray()|]
    let f k = spine.[abs(k.GetHashCode()) % spine.Length]
    Seq.iter (fun (k, v) -> (f k).Add (k, v)) xs
    fun k -> Seq.pick (fun (k', v) -> if k=k' then Some v else None) (f k);;
val hashtbl : seq<'a * 'b> -> ('a -> 'b) when 'a : equality


  Сведения об ответе

lats

09:13, 7th August, 2020

Я думаю, вам нужно быть немного более конкретным. Существует несколько вариантов хэш-таблиц в отношении следующих параметров

  • Является ли хеш-таблица фиксированным размером или динамической?
  • Какой тип функции hash используется?
  • Существуют ли какие-либо ограничения производительности при изменении размера хэш-таблицы?

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

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


  Сведения об ответе

park

04:13, 3rd August, 2020

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

tmpNode->key   = (char*)malloc(strlen(key)+1);   //must have +1 for '\0'
tmpNode->value = (char*)malloc(strlen(value)+1); //must have +1
strcpy(tmpNode->key, key);
strcpy(tmpNode->value, value);

И чтобы завершить код:

HashNode* AppendLinkedNode(HashNode* ptr, char* key, char* value)
{
    //follow pointer till end
    while (ptr->nextEntry!=NULL)
    {
        if (strcmp(ptr->value,value)==0) return NULL;
        ptr=ptr->nextEntry;
    }
    ptr->nextEntry=newNode(key,value);
    return ptr->nextEntry;
}


  Сведения об ответе

lool

18:05, 23rd August, 2020

Я пошел и прочитал несколько страниц Википедии о хешировании: http://en.wikipedia.org/wiki/Hash_table . Кажется, что это большая работа, чтобы создать код для хэш-таблицы здесь, особенно с учетом того, что большинство языков, которые я использую, уже встроены в них. Зачем вам нужны здесь реализации? Этот материал действительно принадлежит библиотеке языков.

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

  • hash функция
  • переменный отсчет ведра
  • поведение при столкновении

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


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться