void IntervalTree::ResolveOverlaps() { // Iterate over all intervals in sorted order, record starts & stops, delete nodes TemplateStack<void *> *intervals = EnumerateDepthFirst(); int nIntervals = intervals->Size(); int *starts = new int[nIntervals]; int *stops = new int[nIntervals]; for(int i=0; i < nIntervals; i++) { IntervalTreeNode *thisNode = (IntervalTreeNode *) (*intervals)[i]; starts[i] = thisNode->GetInterval()->GetLowPoint(); stops[i] = thisNode->GetInterval()->GetHighPoint(); DeleteNode(thisNode); } // Iterate over the sorted intervals to make a tree of non-overlapping intervals for(int i=0; i < nIntervals; i++) { // Find out what the interval overlaps int start = starts[i]; int stop = stops[i]; TemplateStack<void *> * overlapIntervals = EnumerateDepthFirst(start,stop); int nOverlap = overlapIntervals->Size(); IntervalTreeNode *firstOverlap = (IntervalTreeNode *) (*overlapIntervals)[0]; IntervalTreeNode *lastOverlap = (IntervalTreeNode *) (*overlapIntervals)[overlapIntervals->Size()-1]; if(nOverlap==0) { // No overlap, just insert the new interval Insert(new IntInterval(start,stop,1)); } else if(nOverlap==1) { // Deal with the case where there is only one overlapping segment int oStart = firstOverlap->GetInterval()->GetLowPoint(); int oStop = lastOverlap->GetInterval()->GetHighPoint(); double oDepth = firstOverlap->GetInterval()->GetValue(); if(start != oStart || stop != oStop) { // Deal with case where the overlap is not identical if(start == oStart || stop == oStop) { // One of the boundaries matches if(start==oStart) { if(stop<oStop) { Insert(new IntInterval(start,stop,oDepth+1)); Insert(new IntInterval(stop+1,oStop,oDepth)); } else { Insert(new IntInterval(start,oStop,oDepth+1)); Insert(new IntInterval(oStop+1,stop,1)); } } else { if(start<oStart) { Insert(new IntInterval(start,oStart-1,1)); Insert(new IntInterval(oStart,oStop,oDepth+1)); } else { Insert(new IntInterval(oStart,start-1,oDepth)); Insert(new IntInterval(start,oStop,oDepth+1)); } } } else { // no boundary match if(start<oStart) { if(stop<oStop) { Insert(new IntInterval(start,oStart-1,1)); Insert(new IntInterval(oStart,stop,oDepth+1)); Insert(new IntInterval(stop+1,oStop,oDepth)); } else { Insert(new IntInterval(start,oStart-1,1)); Insert(new IntInterval(oStart,oStop,oDepth+1)); Insert(new IntInterval(oStop+1,stop,1)); } } else { if(stop<oStop) { Insert(new IntInterval(oStart,start-1,oDepth)); Insert(new IntInterval(start,stop,oDepth+1)); Insert(new IntInterval(stop+1,oStop,oDepth)); } else { Insert(new IntInterval(oStart,start-1,oDepth)); Insert(new IntInterval(start,oStop,oDepth+1)); Insert(new IntInterval(oStop+1,stop,1)); } } } DeleteNode(firstOverlap); } else { IntInterval *overlap = dynamic_cast<IntInterval *>(firstOverlap->GetInterval()); assert(overlap); overlap->SetValue(oDepth+1); } } else if(nOverlap > 1) { // We overlap more than one interval // Modify first interval int fStart = firstOverlap->GetInterval()->GetLowPoint(); int fStop = firstOverlap->GetInterval()->GetHighPoint(); double fDepth = firstOverlap->GetInterval()->GetValue(); if(start == fStart) { IntInterval *overlap = dynamic_cast<IntInterval *>(firstOverlap->GetInterval()); assert(overlap); overlap->SetValue(fDepth+1); } else { if(start < fStart) { Insert(new IntInterval(start,fStart-1,1)); Insert(new IntInterval(fStart,fStop,fDepth+1)); } else { Insert(new IntInterval(fStart,start-1,fDepth)); Insert(new IntInterval(start,fStop,fDepth+1)); } DeleteNode(firstOverlap); } // Modify last interval int lStart = lastOverlap->GetInterval()->GetLowPoint(); int lStop = lastOverlap->GetInterval()->GetHighPoint(); double lDepth = lastOverlap->GetInterval()->GetValue(); if(stop == lStop) { IntInterval *overlap = dynamic_cast<IntInterval *>(lastOverlap->GetInterval()); assert(overlap); overlap->SetValue(lDepth+1); } else { if(stop < lStop) { Insert(new IntInterval(lStart,stop,lDepth+1)); Insert(new IntInterval(stop+1,lStop,lDepth)); } else { Insert(new IntInterval(lStart,lStop,lDepth+1)); Insert(new IntInterval(lStop+1,stop,1)); } DeleteNode(lastOverlap); } // Increment coverage for all in-between intervals for(int j=1; j < nOverlap-1; j++) { IntervalTreeNode * itnp = static_cast<IntervalTreeNode *>((*overlapIntervals)[j]); assert(itnp); IntInterval *overlap = dynamic_cast<IntInterval *>(itnp->GetInterval()); assert(overlap); overlap->SetValue(overlap->GetValue()+1); } } } delete [] starts; delete [] stops; // A final pass to compact adjacent regions with the same coverage depth intervals = EnumerateDepthFirst(); nIntervals = intervals->Size(); if(nIntervals > 0) { int *newStarts = new int[nIntervals]; int *newStops = new int[nIntervals]; double *newValues = new double[nIntervals]; // initialize IntervalTreeNode *thisNode = (IntervalTreeNode *) (*intervals)[0]; newStarts[0] = thisNode->GetInterval()->GetLowPoint(); newStops[0] = thisNode->GetInterval()->GetHighPoint(); newValues[0] = thisNode->GetInterval()->GetValue(); int newN = 1; double lastValue = thisNode->GetInterval()->GetValue(); int lastStop = newStops[0]; // Iterate through intervals, consolidating where appropriate and deleting tree nodes for(int i=1; i < nIntervals; i++) { IntervalTreeNode *thisNode = (IntervalTreeNode *) (*intervals)[i]; int thisStart = thisNode->GetInterval()->GetLowPoint(); int thisStop = thisNode->GetInterval()->GetHighPoint(); double thisValue = thisNode->GetInterval()->GetValue(); if((thisStart == (lastStop+1)) && (abs(thisValue-lastValue) < 1e-10)) { newStops[newN-1] = thisStop; } else { newStarts[newN] = thisStart; newStops[newN] = thisStop; newValues[newN] = thisValue; newN++; } lastStop = thisStop; lastValue = thisValue; } // Now empty tree and fill it in again for(int i=0; i < nIntervals; i++) { IntervalTreeNode *thisNode = (IntervalTreeNode *) (*intervals)[i]; DeleteNode(thisNode); } for(int i=0; i < newN; i++) { Insert(new IntInterval(newStarts[i],newStops[i],newValues[i])); } delete [] newStarts; delete [] newStops; delete [] newValues; } return; }
int main() { typedef vector<std::size_t> countsVector; #if 0 srand((unsigned)time(NULL)); #else // This will result in test data and a tree that is identical every time as long as the constant below remain unchanged. srand(0); #endif int requestedIntervalsCount = 10000; int requestedQueriesCount = requestedIntervalsCount / 2; int intervalValueLimit = 100000; int intervalLengthLimit = 1000; intervalVector intervals; intervalVector queries; // generate a test set of target intervals for (int i = 0; i < requestedIntervalsCount; ++i) { intervals.push_back(randomInterval<bool>(intervalValueLimit, intervalLengthLimit, intervalValueLimit + 1, true)); } // and queries for (int i = 0; i < requestedQueriesCount; ++i) { queries.push_back(randomInterval<bool>(intervalValueLimit, intervalLengthLimit, intervalValueLimit + 1, true)); } typedef chrono::high_resolution_clock Clock; typedef chrono::milliseconds milliseconds; // using brute-force search countsVector bruteForceCounts; Clock::time_point t0 = Clock::now(); for (intervalVector::iterator q = queries.begin(); q != queries.end(); ++q) { intervalVector results; for (intervalVector::iterator i = intervals.begin(); i != intervals.end(); ++i) { if (i->GetLowPoint() >= q->GetLowPoint() && i->GetHighPoint() <= q->GetHighPoint()) { results.push_back(*i); } } bruteForceCounts.push_back(results.size()); } Clock::time_point t1 = Clock::now(); milliseconds ms = chrono::duration_cast<milliseconds>(t1 - t0); cout << "brute force:\t" << ms.count() << "ms" << endl; // building the interval tree t0 = Clock::now(); intervalTree tree = intervalTree(/*intervals*/); for (intervalVector::iterator i = intervals.begin(); i != intervals.end(); ++i) { tree.Insert(&(*i)); } t1 = Clock::now(); ms = std::chrono::duration_cast<milliseconds>(t1 - t0); cout << "building interval tree:\t" << ms.count() << "ms" << endl; // using the interval tree countsVector treeCounts; t0 = Clock::now(); for (intervalVector::iterator q = queries.begin(); q != queries.end(); ++q) { TemplateStack<void *> *results; results = tree.EnumerateContained(q->GetLowPoint(), q->GetHighPoint()); treeCounts.push_back(results->Size()); delete results; } t1 = Clock::now(); ms = std::chrono::duration_cast<milliseconds>(t1 - t0); cout << "using interval tree:\t" << ms.count() << "ms" << endl; // check that the same number of results are returned countsVector::iterator b = bruteForceCounts.begin(); for (countsVector::iterator t = treeCounts.begin(); t != treeCounts.end(); ++t, ++b) { assert(*b == *t); } return 0; }