线性Hashig ForwardIterator实现begin()和end()

时间:2018-07-27 15:14:00

标签: c++ c++11 iterator hashtable

我正在为基于 Linear Hashing Algorithm 的数据结构实现Iterator。由于此数据结构使用存储桶(数组),每个存储桶可以进一步拥有自己的存储桶(也是数组),并且所有存储桶都通过动态增长的表进行结构化。

要实现begin()方法,我只需将迭代器设置为表中的第一个元素。代码是:

const_iterator begin() const {

    if(this->empty()) { return end(); } //if container is empty return end iterator
    //else return the iterator to first taken element 
    //try only passing to the first element regardless if its full or not cause it shouldnt make a difference
    bucket* next{table[0]};
    element* ptr{next->Bucket};

    return const_iterator{ptr, table};
}

要实现end()方法,我的想法是在表的底部创建一个额外的数组,该数组在插入或结构中的任何操作时都不会使用,其唯一目的是充当结尾。该数组的第一个元素具有值(状态)end,一旦达到该值,end就会被设置为该数组的最后一个元素之后的位置。代码是:

const_iterator end() const { //should point to position behind the last element?
    //find the last taken element in the table
    bucket* next{table[tableSize]};
    element* ptr{next->Bucket}; //cause that one is marked with end and will trigger returning the end

    return const_iterator{ptr, table};
}

负责处理这些请求的迭代器类是:

template <typename Key, size_t N>
class ADS_set<Key, N>::Iterator {
private:
    element* elem{nullptr}; //pointer to element for which the iterator is called
    bucket** tab{nullptr}; //pointer to table

    //find the bucket in which the element for which the constructor was called is in
    bucket* current_bucket{nullptr};
    size_type current_idx{0};
    bool endFound{false};

    void find_current_bucket() {
        bucket* next{tab[current_idx]};

        while(next != nullptr) {
            for(unsigned i=0; i<N; ++i) { //loop through the bucket and its overflows
                if(&(next->Bucket[i]) == elem) {
                    current_bucket = tab[current_idx];
                    return;
                }
            }   

        if(next->overflowBucket != nullptr) {
            next = next->overflowBucket;
        } else {
            ++current_idx;
            if(tab[current_idx]->Bucket[0].state == State::end) {
                endFound = true;
                elem = &(tab[current_idx]->Bucket[N]);
                return;
            }
            next = tab[current_idx];
        }
    }

}

void skip() {
    //set the current bucket
    find_current_bucket();

    if(endFound == true) { return; }

    bucket* next{current_bucket};

    while(next != nullptr) {
        for(unsigned i=0; i<N; ++i) {
            if(&(next->Bucket[i]) == elem) {
                if(elem->state == State::free) {
                    ++elem;
                } else {
                    return; //you found the element
                    //and its not a free place so nothing to skip--> return
                }
            } //goes through each element of bucket
        } //needs to go through overflows as well

        if(next->overflowBucket != nullptr) {
            next = next->overflowBucket;
        } else { //if there is no more overflows and element still not found it has to move to the next index in the table
            ++current_idx;
            if(tab[current_idx]->Bucket[0].state == State::end) {
                elem = &(tab[current_idx]->Bucket[N]);
                //++elem;
                return; //if end return
            }
            next = tab[current_idx];
          }
       }

   }

public:
    using value_type = Key;
    using difference_type = std::ptrdiff_t;
    using reference = const value_type&;
    using pointer = const value_type*;
    using iterator_category = std::forward_iterator_tag;

    explicit Iterator(element* elem = nullptr, bucket** tab = nullptr): elem{elem}, tab{tab} {
        if(elem && tab) {
            skip();
        }
    }

    reference operator*() const { 
        return elem->key;
    }

    pointer operator->() const {
        return &(elem->key);
    }

    Iterator& operator++() {
        ++elem;
        skip();
        return *this;
    }

    Iterator operator++(int) { //increments the pointer but returns the old value
        Iterator copy = *this;
        ++(*this);
        return copy;
    }

    friend bool operator==(const Iterator &lhs, const Iterator &rhs) { return lhs.elem == rhs.elem; }
    friend bool operator!=(const Iterator &lhs, const Iterator &rhs) { return lhs.elem != rhs.elem; }

};

当我使用 Valgrind 测试程序并使用指定的测试程序时,执行以下代码(从测试程序)会出现错误:

void test_iter(ads::set<val_t> const& a, std::set<val_t> const& r) {
    std::cerr << "\n=== test_iter ===\n";

    size_t dist = std::distance(a.begin(), a.end());
    **if(dist != r.size()) {
        std::cerr << RED("[iter] err: range size (distance between begin and end) is wrong.\n"
              << "expected: " << r.size() << ", but got: " << dist << "and begin is: " << *(a.begin()) << '\n');
       dump_compare(a, r);
       std::abort();
    }**

    std::vector<val_t> dump; dump.reserve(a.size());
    for(auto const& v: a) {
        if(!r.count(v)) {
            std::cerr << RED("[iter] err: encountered unexpected value while iterating: " << v << " should not be part of container!\n");
            dump_compare(a, r);
            std::abort();
        }
        dump.push_back(v);
    }

    std::vector<val_t> dump_copy = dump;

    std::sort(dump.begin(), dump.end(), std::less<val_t>{});
    auto last = std::unique(dump.begin(), dump.end(), std::equal_to<val_t>{});
    dump.erase(last, dump.end());

    if(dump.size() != r.size()) {
        std::cerr << RED("[iter] err: had duplicate encounters while iterating. found following elements (in this order):\n\n");

        for(auto const& v: dump_copy) { std::cerr << v << ' '; }
        std::cerr << '\n';

        dump_compare(a, r);
        std::abort();
    }

    ads::set<val_t>::iterator i;
    for(i = a.begin(); i != a.end(); ++i) {
        if(!r.count(*i)) {
            std::cerr << RED("[iter] err: encountered unexpected value while iterating (default iterator constructor): "
                  << *i << " should not be part of container!\n");

            dump_compare(a, r);
            std::abort();
        }
    }
}

更具体地说,当执行代码的合并部分时发生错误,并且错误消息如下(图片如下):

Error message, the distance between begin and end is wrong -> expected dist is 9 and the one I got is 2

我真的不明白为什么会这样,因为我在我的代码或方法中没有发现逻辑上的错误,因此,我很乐意提供有关纠正错误或实现这两种方法的任何建议。

0 个答案:

没有答案