代码之家  ›  专栏  ›  技术社区  ›  Dave

C++中空位跟踪算法的实现

  •  3
  • Dave  · 技术社区  · 16 年前

    我试着用 vacancy tracking algorithm 在C++中实现多维数组的移位。数组以空指针的形式出现,所以我使用地址操作来执行拷贝。

    现在,我使用std::set来填充所有可能的偏移量(0到数组维数的乘法倍)。然后,当我遍历算法时,我从集合中删除。我想这将是最快的,因为我需要随机访问树/集合中的偏移量并删除它们。然后,我需要快速找到下一个未触及/未删除的偏移量。

    其次,删除也很慢。

    第四,确定是否存在任何未触及的偏移量并快速获得其中一个偏移量是一件好事。

    有人对这些问题有什么建议吗?

    3 回复  |  直到 16 年前
        1
  •  1
  •   Potatoswatter    16 年前

    没有读过那篇论文,

    • set::insert set 在下一个 insert
    • 另一方面,如果你一次构建一个集合,你最好使用 vector 和 sort
    • 如果在向量元素旁边添加指向的指针,则从已排序的向量中删除很容易。
      • 初始化 next = NULL . 如果 next == NULL ,元素有效(尚未删除)。
      • next = this+1 .
      • this+1 到第一个元素,其中 iter->next != iter+1 if ( iter->next == NULL ) return iter; else return iter->next;
      • (this+1)->next = iter (or) iter->next 之前 return
      • 在末尾添加一个保护元素 next == this . 这个,不是 vector::end ,表示序列的结束。

    这是初稿,我把它编好了。未测试;请随意编辑它或让我使它成为一个维基。或者让我知道我不能保证花更多的时间在它上面的错误。我还没完成 clear erase 不会破坏分类对象;那要等到 sorted_skip_array 被摧毁了。

    #include <vector>
    
    template< class T, class Alloc >
    class skip_array_base {
    protected:
        struct node {
            node *prev, *next;
            T val;
    
            node( T const &x = T() ) : prev(), next(), val(x) {}
        };
        typedef typename Alloc::template rebind< node >::other allocator_type;
    
        typedef std::vector< node, allocator_type > vector_type;
        typedef typename vector_type::iterator vector_iterator;
        vector_type v;
    
        skip_array_base( allocator_type const &a = allocator_type() ) : v( a ) {}
        skip_array_base( skip_array_base const &in ) : v( in.v ) {}
        skip_array_base( typename vector_type::size_type s,
            typename vector_type::value_type const &x, allocator_type const &a )
            : v( s, x, a ) {}
    
        template< class Tcv >
        struct iter : vector_iterator {
            typedef T value_type;
            typedef Tcv &reference;
            typedef Tcv *pointer;
    
            iter() {}
            iter( vector_iterator const &in )
                : vector_iterator( in ) {}
    
            reference operator*() { return vector_iterator::operator*().val; }
            pointer operator->() { return &vector_iterator::operator*().val; }
            reference operator[]( typename vector_iterator::difference_type n )
                { return vector_iterator::operator[]( n ).val; }
    
            iter &operator++() { vector_iterator::operator++(); return *this; }
            iter operator++(int) { return vector_iterator::operator++(0); }
            iter &operator--() { vector_iterator::operator--(); return *this; }
            iter operator--(int) { return vector_iterator::operator--(0); }
    
            iter &operator+=( typename vector_iterator::difference_type n )
                { vector_iterator::operator+=( n ); return *this; }
            iter operator+( typename vector_iterator::difference_type n )
                { return vector_iterator::operator+( n ); }
            iter &operator-=( typename vector_iterator::difference_type n )
                { vector_iterator::operator-=( n ); return *this; }
            iter operator-( typename vector_iterator::difference_type n )
                { return vector_iterator::operator-( n ); }
        };
    
    public:
        typedef typename vector_type::size_type size_type;
    
        void swap( skip_array_base &r ) { v.swap( r.v ); }
        skip_array_base &operator=( skip_array_base const &x ) {
            v = x.v;
            return *this;
        }
    
        size_type size() const { return v.size() - 2; }
        size_type max_size() const { return v.max_size() - 2; }
        bool empty() const { return v.size() > 2; }
    
        bool operator== ( skip_array_base const &r ) const { return v == r.v; }
        bool operator!= ( skip_array_base const &r ) const { return v != r.v; }
        bool operator< ( skip_array_base const &r ) const { return v < r.v; }
        bool operator> ( skip_array_base const &r ) const { return v > r.v; }
        bool operator<= ( skip_array_base const &r ) const { return v <= r.v; }
        bool operator>= ( skip_array_base const &r ) const { return v >= r.v; }
    
        void clear() { v.erase( ++ v.begin(), -- v.end() ); }
    };
    
    template< class T, class Alloc >
    class sorted_skip_array;
    
    template< class T, class Alloc = std::allocator<T> >
    class skip_array_prelim : public skip_array_base< T, Alloc > {
        typedef skip_array_base< T, Alloc > base;
        typedef typename base::vector_type vector_type;
        using skip_array_base< T, Alloc >::v;
    
    public:
        typedef T value_type;
        typedef typename Alloc::reference reference;
        typedef typename Alloc::const_reference const_reference;
        typedef typename base::template iter< value_type > iterator;
        typedef typename base::template iter< const value_type > const_iterator;
        typedef typename vector_type::difference_type difference_type;
        typedef typename vector_type::size_type size_type;
        typedef typename vector_type::allocator_type allocator_type;
    
        skip_array_prelim( allocator_type const &a = allocator_type() )
            : base( 2, value_type(), a ) {}
        skip_array_prelim( skip_array_prelim const &in )
            : base( in ) {}
        skip_array_prelim( size_type s, value_type const &x = value_type(),
            allocator_type const &a = allocator_type() )
            : base( s + 2, x, a ) {}
    
        template< class I >
        skip_array_prelim( I first, I last,
            allocator_type const &a = allocator_type(),
            typename I::pointer = typename I::pointer() )
            : base( 1, value_type(), a ) {
            v.insert( v.end(), first, last );
            v.push_back( value_type() );
        }
    
        iterator begin() { return ++ v.begin(); }
        iterator end() { return -- v.end(); }
        const_iterator begin() const { return ++ v.begin(); }
        const_iterator end() const { return -- v.end(); }
    
        reference operator[]( size_type n ) { return v[ n + 1 ]; }
        const_reference operator[]( size_type n ) const { return v[ n + 1 ]; }
    
        iterator insert( iterator pos, value_type const &x )
            { return v.insert( pos, x ); }
        iterator insert( iterator pos, size_type n, value_type const &x )
            { return v.insert( pos, n, x ); }
        template< class I >
        iterator insert( iterator pos, I first, I last,
            typename I::pointer = typename I::pointer() )
            { return v.insert( pos, first, last ); }
    
        iterator erase( iterator i ) { return v.erase( i ); }
        iterator erase( iterator first, iterator last )
            { return v.erase( first, last ); }
    };
    
    template< class T, class Alloc = std::allocator<T> >
    class sorted_skip_array : public skip_array_base< T, Alloc > {
        typedef skip_array_base< T, Alloc > base;
        typedef typename base::vector_type vector_type;
        typedef typename vector_type::iterator vector_iterator;
        typedef typename base::node node;
        using skip_array_base< T, Alloc >::v;
    
        template< class Tcv >
        struct iter : base::template iter< Tcv > {
            typedef std::bidirectional_iterator_tag iterator_category;
            typedef Tcv &reference;
            typedef Tcv *pointer;
    
            iter() {}
            iter( vector_iterator const &x ) : base::template iter< Tcv >( x ) {}
    
            iter &operator++() { increment< &node::next, 1 >(); return *this; }
            iter operator++(int)
                { iter r = *this; increment< &node::next, 1 >(); return r; }
            iter &operator--() { increment< &node::prev, -1 >(); return *this; }
            iter operator--(int)
                { iter r = *this; increment< &node::prev, -1 >(); return r; }
    
        private:
            template< node *node::*link, int inc >
            void increment() {
                vector_iterator memo = *this; // un-consts a const_iterator
                node *pen = &*( memo += inc );
                while ( pen->*link && pen->*link != pen ) pen = pen->*link;
                *this = iter( vector_iterator( (*memo).*link = pen ) );
            }
        };
    
    public:
        typedef T value_type;
        typedef typename Alloc::reference reference;
        typedef typename Alloc::const_reference const_reference;
        typedef iter< T > iterator;
        typedef iter< const T > const_iterator;
        typedef typename vector_type::difference_type difference_type;
        typedef typename vector_type::size_type size_type;
    
        sorted_skip_array( skip_array_prelim<T,Alloc> &x ) {
            sort( x.begin(), x.end() );
            swap( x );
        }
    
        iterator begin() { return ++ iterator( v.begin() ); }
        iterator end() { return iterator( -- v.end() ); }
        const_iterator begin() const { return ++ const_iterator( v.begin() ); }
        const_iterator end() const { return const_iterator( -- v.end() ); }
    
        iterator erase( iterator i ) {
            vector_iterator vi = i;
            vi->prev = &* vi[-1];
            vi->next = &* vi[1];
            //vi->val->~value_type(); // don't bother with allocator rigmarole
            return ++ i;
        }
        iterator erase( iterator first, iterator last ) {
            if ( first != last ) {
                vector_iterator vf = first, vl = last - 1;
                vl->prev = &* vf[-1];
                vf->next = &* vl[1];
            }
            return last;
        }
    };
    
        2
  •  0
  •   Billy ONeal IS4    16 年前

    我不是百分之百确定,但你能用一下吗 std::next_permutation

    您可能还需要考虑创建一个固定数组,而不是一个集合。即使该数组需要存储的元素是要执行的集合的3倍,也要记住,std::集合中的每个节点可能至少占用了两个指针的空间,以及所讨论的数据元素。因此,在动态分配中,您应该节省空间并提高速度。

    std::binary_search 会表现得比 std::set 标准::集 相比之下,它针对交错插入和删除进行了优化。如果插入和删除是分开的,只需对向量排序并使用二进制搜索。您可能希望使用某种标志来标记已从向量中删除,而不是每次实际删除以减少复制。这样整个向量就可以立刻被摧毁。

    希望有帮助:)

        3
  •  0
  •   Dave    16 年前

    我找到了比电视机快12倍的最佳方法。我用一个 boost dynamic_bitset

    编辑:万一将来有人读到这个。。。这种算法的速度并不比标准的复制和写回方法快,这种方法使用的是正常大小(4-8字节)的数据元素。对于较大的数据大小(例如,如果要复制较大的结构,例如128字节),它的速度很快。