문제

내가 찾는 컨테이너지도에서 두 번체 포인터입니다.그러나 각각의 핵심은 단순히 범위 복식의 것에 해당하는 객체입니다.

예를 들어 있는 키/값 쌍의 <(0.0 3.0),ptr>,또는 <(3.5 10.0),ptr2>

컨테이너[1.0]반환해야 합니다 ptr,컨테이너[3.0]반환해야합니다 ptr 및 컨테이너[-1.0]을 정의되지 않습니다.

어떤 객체와 유사한 행동에 의해 또는 기본 것이다 나는 그것을 구현하는가?

편집

여기에 실제 코드는 내가 작성할 수 있습 쉽게 디버깅/에 대한 조언을 제공합니다.

// Behavior: A range is defined mathematically as (min, max]

class dblRange
{
public:
    double min;
    double max;

    dblRange(double min, double max)
    {
        this->min = min;
        this->max = max;
    };

    dblRange(double val)
    {
        this->min = val;
        this->max = val;
    };

    int compare(const dblRange rhs)
    {
        // 1 if this > rhs
        // 0 if this == rhs
        //-1 if this < rhs
        if (rhs.min == rhs.max && min == max)
        {
            /*if (min > rhs.min)
                return 1;
            else if (min == rhs.min)
                return 0;
            else
                return -1;*/
            throw "You should not be comparing values like this. :(\n";
        }
        else if (rhs.max == rhs.min)
        {
            if (min > rhs.min) 
                return 1;
            else if (min <= rhs.min && max > rhs.min)
                return 0;
            else // (max <= rhs.min)
                return -1;
        }
        else if (min == max)
        {
            if (min >= rhs.max)
                return 1;
            else if (min < rhs.max && min >= rhs.min)
                return 0;
            else // if (min < rhs.min
                return -1;
        }

        // Check if the two ranges are equal:
        if (rhs.min == min && rhs.max == max)
        {
            return 0;
        }
        else if (rhs.min < min && rhs.max <= min)
        {
            // This is what happens if rhs is fully lower than this one.
            return 1;
        }
        else if (rhs.min > min && rhs.min >= max)
        {
            return -1;
        }
        else
        {
            // This means there's an undefined case. Ranges are overlapping, 
            // so comparisons don't work quite nicely.

            throw "Ranges are overlapping weirdly. :(\n";
        }
    };

    int compare(const dblRange rhs) const
    {
        // 1 if this > rhs
        // 0 if this == rhs
        //-1 if this < rhs
        if (rhs.min == rhs.max && min == max)
        {
            /*if (min > rhs.min)
                return 1;
            else if (min == rhs.min)
                return 0;
            else
                return -1;*/
            throw "You should not be comparing values like this. :(\n";
        }
        else if (rhs.max == rhs.min)
        {
            if (min > rhs.min) 
                return 1;
            else if (min <= rhs.min && max > rhs.min)
                return 0;
            else // (max <= rhs.min)
                return -1;
        }
        else if (min == max)
        {
            if (min >= rhs.max)
                return 1;
            else if (min < rhs.max && min >= rhs.min)
                return 0;
            else // if (min < rhs.min
                return -1;
        }

        // Check if the two ranges are equal:
        if (rhs.min == min && rhs.max == max)
        {
            return 0;
        }
        else if (rhs.min < min && rhs.max <= min)
        {
            // This is what happens if rhs is fully lower than this one.
            return 1;
        }
        else if (rhs.min > min && rhs.min >= max)
        {
            return -1;
        }
        else
        {
            // This means there's an undefined case. Ranges are overlapping, 
            // so comparisons don't work quite nicely.

            throw "Ranges are overlapping weirdly. :(\n";
        }
    };

    bool operator== (const dblRange rhs ) {return (*this).compare(rhs)==0;};
    bool operator== (const dblRange rhs ) const {return (*this).compare(rhs)==0;};
    bool operator!= (const dblRange rhs ) {return (*this).compare(rhs)!=0;};
    bool operator!= (const dblRange rhs ) const {return (*this).compare(rhs)!=0;};
    bool operator< (const dblRange rhs ) {return (*this).compare(rhs)<0;};
    bool operator< (const dblRange rhs ) const {return (*this).compare(rhs)<0;};
    bool operator> (const dblRange rhs ) {return (*this).compare(rhs)>0;};
    bool operator> (const dblRange rhs ) const {return (*this).compare(rhs)>0;};
    bool operator<= (const dblRange rhs ) {return (*this).compare(rhs)<=0;};
    bool operator<= (const dblRange rhs ) const {return (*this).compare(rhs)<=0;};
    bool operator>= (const dblRange rhs ) {return (*this).compare(rhs)>=0;};
    bool operator>= (const dblRange rhs ) const {return (*this).compare(rhs)>=0;};

};

지금 문제가 있음을 지도 받아들이블로 키도 비교 연산자의 자리를 지키고 있습니다.

여기에 몇 가지 운전을하는 코드 사용을 테스트하는 경우 작동:

std::map<dblRange, int> map;
map[dblRange(0,1)] = 1;
map[dblRange(1,4)] = 2;
map[dblRange(4,5)] = 3;

map[3.0] = 4;
도움이 되었습니까?

해결책

수업을 만듭니다 DoubleRange 이중 범위를 저장하고 비교 연산자를 구현합니다. 그런 식으로, std::map 나머지는 당신과 함께 할 것입니다 DoubleRange 키로 클래스.

다른 팁

나는 당신이 범위를 정의 할 수 있다는 점에서 Earwicker와 동의합니다. 이제는 실제 의미를 가진 연산자를 구현하는 데 찬성합니다 (기본 유형이하는 일 : 두 범위가 동일하게 비교됩니다). 그런 다음 세 번째 맵 매개 변수를 사용 하여이 맵의 특정 문제를 해결하는 비교 함수 (또는 함수)를 전달할 수 있습니다.

// Generic range, can be parametrized for any type (double, float, int...)
template< typename T >
class range
{
public:
    typedef T value_type;

    range( T const & center ) : min_( center ), max_( center ) {}
    range( T const & min, T const & max )
        : min_( min ), max_( max ) {}
    T min() const { return min_; }
    T max() const { return max_; }
private:
    T min_;
    T max_;
};

// Detection of outside of range to the left (smaller values):
//
// a range lhs is left (smaller) of another range if both lhs.min() and lhs.max() 
// are smaller than rhs.min().
template <typename T>
struct left_of_range : public std::binary_function< range<T>, range<T>, bool >
{
    bool operator()( range<T> const & lhs, range<T> const & rhs ) const
    {
        return lhs.min() < rhs.min()
            && lhs.max() <= rhs.min();
    }
};
int main()
{
    typedef std::map< range<double>, std::string, left_of_range<double> > map_type;

    map_type integer; // integer part of a decimal number:

    integer[ range<double>( 0.0, 1.0 ) ] = "zero";
    integer[ range<double>( 1.0, 2.0 ) ] = "one";
    integer[ range<double>( 2.0, 3.0 ) ] = "two";
    // ...

    std::cout << integer[ range<double>( 0.5 ) ] << std::endl; // zero
    std::cout << integer[ range<double>( 1.0 ) ] << std::endl; // one
    std::cout << integer[ 1.5 ] << std::endl; // one, again, implicit conversion kicks in
}

이중 값 사이의 평등과 비교에주의해야합니다. 같은 가치 (실제 세계)에 도달하는 다른 방법은 약간 다른 부동 소수점 결과를 산출 할 수 있습니다.

사용하는 것이 좋습니다 간격 트리 데이터 구조. Boost는 구현이 있습니다 간격 컨테이너 라이브러리

한 가지 방법은 손에 "브레이크 포인트"를 계산하는 것입니다.

typedef vector< tuple<double, double, foo*> > collisionlist_t;
const collisionlist_t vec;
vec.push_back(make_tuple(0.0, 3.0, ptr));
vec.push_back(make_tuple(3.5, 10.0, ptr2));
// sort 
std::map<double, foo*> range_lower_bounds;
for(collisionlist_t::const_iterator curr(vec.begin()), end(vec.end()); curr!=end; ++curr)
{
    /* if ranges are potentially overlapping, put some code here to handle it */
    range_lower_bounds[curr->get<0>()] = curr->get<2>();
    range_lower_bounds[curr->get<1>()] = NULL;
}

double x = // ...
std::map<double, foo*>::const_iterator citer = range_lower_bounds.lower_bound(x);

또 다른 제안 : 수학적 변환을 사용하여 직접 비교할 수있는 실제에서 Int로 인덱스를 매핑하십시오.

이러한 범위가 여러 개 있고 밀도가 높으면 도움이 될 수있는 "간격 트리"라고 알려진 구조도 있습니다.

은 간격으로 개방 또는 폐쇄 또는 반?내가 가 닫혔습니다.주 간격으로 겹칠 수 없습으로 정의됩니다.당신은 또한 분할에 대한 규칙을 때 하나 삽입을 통해 쌓는 간격.규칙이 필요하여 위치를 결정할 고려해야합니다 부동 소수점 엡실론.

이 구현을 사용하여 지도::lower_bound 과하지 않는 클래스를 사용하의 도메인으로 지도

지도::lower_bound 반복기를 반환합에서 첫 번째 요소는지도와 함께 키 값과 동일한 또는 더 큰 것보다는 지정된 키.(즉,적어도 키 보다 크거나 같은 K.불행한 선택의 STL 메서드 이름으로 그것이 최소한의 상 K.)

template <class codomain>
class RangeMap : private std::map<double,std::pair<double,codomain>{
public:
    typedef double domain;
    typedef std::map<double,std::pair<double,codomain>:: super;
    typename super::value_type value_type;
protected:
    static domain& lower(const value_type& v){
        return v.first;
    }

    static domain& upper(const value_type& v){
        return v.second.first;
    }

    static codomain& v(const value_type& v){
        return v.second.second;
    }

public:

    static const domain& lower(const value_type& v){
        return v.first;
    }
    static const domain& upper(const value_type& v){
        return v.second.first;
    }
    static const codomain& v(const value_type& v){
        return v.second.second;
    }


    static bool is_point(const value_type& vf) {
        return lower(v) == upper(v);
    }

    static bool is_in(const domain& d,const value_type& vf) {
        return (lower(v) <= d) && (d <= upper(v));
    }


    const_iterator greatest_lower_bound(const domain& d)const {
        const_iterator j = super::lower_bound(d);
        if(j!=end() && j->first==d) return j;//d is the lh side of the closed interval
                                             //remember j->first >= d because it was lower but its the first
        if(j==begin()) return end();//d < all intervals
        --j;                        //back up
        return j;
    }
    const_iterator find(domain& d) {
        const_iterator j = greatest_lower_bound(d);
        if (is_in(j,d)) return j;
        return end();
    }
    iterator greatest_lower_bound(const domain& d) {
        iterator j = super::lower_bound(d);
        if(j!=end() && j->first==d) return j;//d is the lh side of the closed interval
                                             //remember j->first >= d because it was lower but its the first
        if(j==begin()) return end();//d < all intervals
        --j;                        //back up
        return j;
    }
    const_iterator find(domain& d) const{
        iterator j = greatest_lower_bound(d);
        if (is_in(j,d)) return j;
        return end();
    }  //so much for find(d) 
    iterator find(domain& d){
        iterator j = greatest_lower_bound(d);
        if (is_in(j,d)) return j;
        return end();
    }  //so much for find(d) 

     struct overlap: public std::exception{
     };
     bool erase(const double lhep,const double rhep);
     //you have a lot of work regarding splitting intervals erasing when overlapped
     //but that can all be done with erase, and insert below. 
     //erase may need to split too
     std::pair<iterator,bool>
     split_and_or_erase_intervals(const double lhep,
                                  const double rhep, 
                                  const codomain& cd);
     //the insert method - note the addition of the overwrtite 
     std::pair<iterator,bool>
     insert(const double lhep,const double rhep,const codomain& cd,bool overwrite_ok){
          if( find(lhep)!=end() || find(rhep)!=end() ) {
              if(overwrite_ok){
                 return split_and_or_erase_intervals(const double lhep,
                                                     const double rhep, 
                                                     const codomain& cd);
              }
              throw overlap();
          }
          return insert(value_type(lhep,pair<double,codomain>(rhep,cd)));
     }
 };

간격이 겹치지 않아야하는 경우 삽입 시간 에이 속성을 확인하기 위해 추가 코드를 추가해야합니다. 구체적으로, 당신이 주장하고자하는 속성은 새로운 간격이 이전에 비어있는 범위 내에 있다는 것입니다. 이 작업을 수행하는 쉬운 방법은 허용하는 것입니다 범위의 유형 : "점령"및 "빈". 사용 가능한 전체 범위를 다루는 단일 "빈"항목을 만들어 시작해야합니다. 새로운 "점유"범위의 삽입에는 다음이 필요합니다.

(1) 새로운 범위 내에서 일부 가치를 조회하십시오.
(2) 반환 된 범위가 비어 있고 완전히 새로운 범위를 포함하는지 확인하십시오. (이것은 위의 필수 주장이었습니다)
(3) 반환 된 빈 범위를 수정하여 끝이 새 범위의 시작 부분에 놓여 있습니다. (4) 새 범위의 끝에서 시작되는 새로운 빈 범위를 삽입하고 반환 된 범위의 기존 끝에서 끝납니다.
(5) 새로운 범위를 삽입하여 빈 범위로 둘러싸여 있다고 확신합니다.
(6) 다른 점유 범위에서 분리하는 빈 공간이없는 새로운 점유 범위를 삽입 할 때 추가 코너 케이스가있을 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top