java - как создать собственный итератор хеш-таблицы?

В настоящее время я пытаюсь реализовать коллекцию Hashtable - у меня все запущено и работает, но я столкнулся с концептуальной проблемой, когда пытался определить собственный итератор для таблицы. У меня есть внутренний класс под названием «HashEntry», который представляет собой фактические объекты, хранящиеся в массиве, — они хранят ключ, значение и статус записи, т. Е. Пусто, активно, удалено.

private class HashEntry
{
    private TKey m_key;
    private TValue m_value;
    private EntryStatus status;

    //standard constructor
    public HashEntry(TKey key, TValue value)
    {
        m_key = key;
        m_value = value;
        status = EntryStatus.ACTIVE;
    }

    public HashEntry(TKey key, TValue value, EntryStatus i) {
        m_key = key;
        m_value = value;
        status = i;
    }

    //default 'empty' constructor
    public HashEntry()
    {
        //calls default constructor, creates placeholder entry
        m_key = null;
        m_value = null;
        status = EntryStatus.EMPTY;
    }

    //equals operator override, this override just compares compares
    // the objects held in the entry, so any object used with this
    // implementation must hae=ve its own equals override
    @Override
    public boolean equals(Object obj)
    {
        if (obj == null) { return false; }
        if (getClass() != obj.getClass()) { return false; }

        final HashEntry other = (HashEntry) obj;
        return (!((this.m_key == null) ? (other.m_key != null) : !this.m_key.equals(other.m_key)));
    }

    // override of the hashCode() function--just calls the hashCode
    // function of the embedded object, so that must be provided
    @Override
    public int hashCode()
    {
        return this.m_key.hashCode();
    }

    // toString override just returns the toString of the embedded object
    @Override
    public String toString()
    {
        StringBuilder sb = new StringBuilder();
        sb.append(m_key.toString()).append(m_value.toString());
        return sb.toString();
    }
}

Это первая часть моего вопроса: если я хочу иметь возможность перебирать таблицу, должен ли я перебирать (и, следовательно, возвращать) объекты HashEntry, или это соглашение хеш-таблицы для перебора фактического значения, хранящегося в таблице ? Класс HashEntry является закрытым, поэтому я предполагаю, что его плохая практика - возвращать его экземпляры...

Но если это так, как мне создать итератор Hashtable, который выполняет итерацию по своим объектам HashEntry? Должен ли я определять итератор/итерируемый объект в классе HashEntry?


person Ben Granger    schedule 08.06.2015    source источник
comment
Стандартная реализация хэш-карты не сохраняет порядок вставки, вы уверены, что ваш алгоритм это делает?   -  person Elliott Frisch    schedule 08.06.2015
comment
Меня не очень беспокоит порядок вставки (который алгоритм не сохраняет - итератор на самом деле будет только для внутреннего использования, так что я могу писать методы, которые по существу удаляют таблицу чисто, а также выполняют итерацию в любом другом методе .   -  person Ben Granger    schedule 08.06.2015
comment
По крайней мере, сделайте HashEntry общим, как HashEntry<TKey, TValue>.   -  person Elliott Frisch    schedule 08.06.2015


Ответы (1)


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

Почему бы вам просто не сделать класс HashEntry общим внутренним классом public static и сделать вещи, специфичные для реализации, private? Вам, вероятно, также потребуется сделать HashEntry универсальным, потому что я предполагаю, что ваш родительский класс (назовем его просто MyHashTable) также является универсальным на основе TKey и TValue.

Итак, на вашем месте я бы сделал так, чтобы ваши HashEntry и MyHashTable выглядели примерно так:

// Note: implements Iterable<E> now
public class MyHashTable<TKey, TValue> implements Iterable<MyHashTable.HashEntry<TKey, TValue>>
{
    public Iterator<MyHashTable.HashEntry<TKey, TValue>> iterator() {
        // ...
        // Make and return your iterator here
        // ...
    }

    // Note: public and generic now
    public static class HashEntry<TKey, TValue>
    {
        private TKey m_key;
        private TValue m_value;
        private EntryStatus status;

        //standard constructor
        // Note: private now
        public HashEntry(TKey key, TValue value)
        {
            m_key = key;
            m_value = value;
            status = EntryStatus.ACTIVE;
        }

        // Note: private now
        private HashEntry(TKey key, TValue value, EntryStatus i) {
            m_key = key;
            m_value = value;
            status = i;
        }

        //default 'empty' constructor
        // Note: private now
        public HashEntry()
        {
            //calls default constructor, creates placeholder entry
            m_key = null;
            m_value = null;
            status = EntryStatus.EMPTY;
        }

        public TKey getKey() {
            return m_key;
        }

        public TValue getValue() {
            return m_value;
        }

        public EntryStatus getEntryStatus() {
            return status;
        }

        //equals operator override, this override just compares compares
        // the objects held in the entry, so any object used with this
        // implementation must hae=ve its own equals override
        @Override
        public boolean equals(Object obj)
        {
            if (obj == null) { return false; }
            if (getClass() != obj.getClass()) { return false; }

            final HashEntry other = (HashEntry) obj;
            return (!((this.m_key == null) ? (other.m_key != null) : !this.m_key.equals(other.m_key)));
        }

        // override of the hashCode() function--just calls the hashCode
        // function of the embedded object, so that must be provided
        @Override
        public int hashCode()
        {
            return this.m_key.hashCode();
        }

        // toString override just returns the toString of the embedded object
        @Override
        public String toString()
        {
            StringBuilder sb = new StringBuilder();
            sb.append(m_key.toString()).append(m_value.toString());
            return sb.toString();
        }
    }
}

Обратите внимание, что HashEntry теперь является внутренним классом MyHashTable, он общий, и его конструкторы теперь private. Это гарантирует, что никто, кроме внешнего класса MyHashTable, не сможет создать экземпляр HashEntry, потому что создание экземпляра за пределами вашей хеш-таблицы не имеет смысла (см. this ). Однако другие люди могут получить доступ к ключам и значениям записи через геттеры.

Сам итератор будет экземпляром Iterator<MyHashTable.HashEntry<TKey, TValue>>. Что касается его написания, это зависит от вашей собственной реализации хеш-таблицы, но в основном вам нужен способ получить следующий элемент в любой последовательности: Iterator<E>.next().

Например, вот реализация метода iterator(), которая перебирает простой массив:

private Type[] arrayList;
private int currentSize;

@Override
public Iterator<Type> iterator() {
    Iterator<Type> it = new Iterator<Type>() {

        private int currentIndex = 0;

        @Override
        public boolean hasNext() {
            return currentIndex < currentSize && arrayList[currentIndex] != null;
        }

        @Override
        public Type next() {
            return arrayList[currentIndex++];
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }
    };
    return it;
}

(источник: https://stackoverflow.com/a/5849625/837703)

Надеюсь, это немного помогло.

person Community    schedule 08.06.2015
comment
Отлично, спасибо @dudeprgm, я не думал о том, чтобы сделать класс HashEntry общедоступным, хотя мне, вероятно, придется предоставить некоторые примечания о том, как его следует использовать, теперь, когда это возможно. Спасибо, ребята, это очень помогает. - person Ben Granger; 08.06.2015