Stroustrup的hash_map的实现是错误的?

时间:2016-09-18 16:49:40

标签: c++ hash stl hashmap

我正在研究Straustrup的hash_map实现。这将直截了当地说明他是如何实施的

template<class Key, class T, class H = Hash<Key>, class EQ = equal_to<Key>, class A = allocator<T> >
class hash_map
{
private: // representation
    struct Entry {
        key_type key;
        mapped_type val;
        Entry* next; // hash overflow link
        bool erased;
        Entry(key_type k, mapped_type v, Entry* n)
        : key(k), val(v), next(n), erased(false) { }
    };

    vector<Entry> v; // the actual entries
    vector<Entry*> b; // the hash table: pointers into v
    // ...

private:
    float max_load; // keep v.size()<=b.size()*max_load
    float grow; // when necessary, resize(bucket_count()*grow)
    size_type no_of_erased; // number of entries in v occupied by erased elements
    Hasher hash; // hash function
    key_equal eq; // equality
    const T default_value; // default value used by []
};

这是operator []

的实现
template<class Key, class T, class H = Hash<Key>, class EQ = equal_to<Key>, class A = allocator<T> >
mapped_type& hash_map::operator[](const key_type& k)
{
    size_type i = hash(k)%b.size(); // hash
    for(Entry* p = b[i]; p; p = p->next) // search among entries hashed to i
        if (eq(k,p->key)) { // found
            if (p->erased) { // re-insert
                p->erased = false;
                no_of_erased--;
                return p->val = default_value;
            }
            return p->val;
        }

    // not found:
    if (b.size()*max_load < v.size()) { // if ‘‘too full’’
        resize(b.size()*grow); // grow
        return operator[](k); // rehash
    }

    v.push_back(Entry(k,default_value,b[i])); // add Entry
    b[i] = &v.back(); // point to new element
    return b[i]->val;
}

所以,让我们想象有3个元素映射到散列i,但它们都不对应新密钥k,那么我们应该在列表中添加另一个条目{{ 1}},对吗?相反,代码会在b[i]向量中创建另一个Entry,并将v替换为该条目的地址(从而丢失旧的3个条目)。

我是否遗漏了某些内容,或者确实存在问题?

P.S。我正在研究&#34; C ++编程语言&#34;作者:Bjarne Straustrup,第三版。该功能在第500页。

1 个答案:

答案 0 :(得分:2)

哈希条目形成链表。插入新条目时,它将被赋予条目列表的前一个头部(可能为null):

Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Index: 62523, Size: 7524
at java.util.ArrayList.rangeCheck(ArrayList.java:653)
at java.util.ArrayList.get(ArrayList.java:429)
at GoodsView$GoodsViewTableModel.getPosition(Main.java:205)
at GoodsView$GoodsViewTableModel.getValueAt(Main.java:178)
at javax.swing.table.TableRowSorter$TableRowSorterModelWrapper.getValueAt(TableRowSorter.java:269)
at javax.swing.DefaultRowSorter.compare(DefaultRowSorter.java:955)
at javax.swing.DefaultRowSorter.access$100(DefaultRowSorter.java:112)
at javax.swing.DefaultRowSorter$Row.compareTo(DefaultRowSorter.java:1376)
at javax.swing.DefaultRowSorter$Row.compareTo(DefaultRowSorter.java:1366)
at java.util.Arrays.binarySearch0(Arrays.java:2439)
at java.util.Arrays.binarySearch(Arrays.java:2379)
at javax.swing.DefaultRowSorter.insertInOrder(DefaultRowSorter.java:1000)
at javax.swing.DefaultRowSorter.rowsInserted0(DefaultRowSorter.java:1058)
at javax.swing.DefaultRowSorter.rowsInserted(DefaultRowSorter.java:868)
at javax.swing.JTable.notifySorter(JTable.java:4270)
at javax.swing.JTable.sortedTableChanged(JTable.java:4118)
at javax.swing.JTable.tableChanged(JTable.java:4395)
at javax.swing.table.AbstractTableModel.fireTableChanged(AbstractTableModel.java:296)
at javax.swing.table.AbstractTableModel.fireTableRowsInserted(AbstractTableModel.java:231)
at GoodsView$GoodsViewTableModel.addPositions(Main.java:215)
at GoodsView$2.process(Main.java:113)
at javax.swing.SwingWorker$3.run(SwingWorker.java:414)
at sun.swing.AccumulativeRunnable.run(AccumulativeRunnable.java:112)
at javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.run(SwingWorker.java:832)
at sun.swing.AccumulativeRunnable.run(AccumulativeRunnable.java:112)
at javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.actionPerformed(SwingWorker.java:842)
at javax.swing.Timer.fireActionPerformed(Timer.java:313)
at javax.swing.Timer$DoPostEvent.run(Timer.java:245)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at javax.swing.DefaultRowSorter.getViewToModelAsInts(DefaultRowSorter.java:742)
at javax.swing.DefaultRowSorter.sort(DefaultRowSorter.java:572)
at javax.swing.DefaultRowSorter.shouldOptimizeChange(DefaultRowSorter.java:1025)
at javax.swing.DefaultRowSorter.rowsInserted(DefaultRowSorter.java:867)
at javax.swing.JTable.notifySorter(JTable.java:4270)
at javax.swing.JTable.sortedTableChanged(JTable.java:4118)
at javax.swing.JTable.tableChanged(JTable.java:4395)
at javax.swing.table.AbstractTableModel.fireTableChanged(AbstractTableModel.java:296)
at javax.swing.table.AbstractTableModel.fireTableRowsInserted(AbstractTableModel.java:231)
at GoodsView$GoodsViewTableModel.addPositions(Main.java:215)
at GoodsView$2.process(Main.java:113)
at javax.swing.SwingWorker$3.run(SwingWorker.java:414)
at sun.swing.AccumulativeRunnable.run(AccumulativeRunnable.java:112)
at javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.run(SwingWorker.java:832)
at sun.swing.AccumulativeRunnable.run(AccumulativeRunnable.java:112)
at javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.actionPerformed(SwingWorker.java:842)
at javax.swing.Timer.fireActionPerformed(Timer.java:313)
at javax.swing.Timer$DoPostEvent.run(Timer.java:245)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

请参阅那里的v.push_back(Entry(k,default_value,b[i])); // add Entry

然后在b[i]字段中创建该条目的链接。然后,我们移动列表next的头部以指向新条目;

b[i]