有一组积分(比如说100,000点)。我尝试做的是
找到四个极值点(最小x和y,最大x和y)
丢弃前四个极端点内的点
在剩下的点中找出接下来的四个极值点。 (直到没有任何一点。在代码中,当找到第二个四个极值点时它停止。)
我以两种方式实现了这一点。
第一种方法:从点集中删除点
第二种方式:只保存剩余的点数'从点集中索引并使用索引来查找下一个极值点。
我的问题是我测量了每个算法(firstAlgorithm和secondAlgorithm)所花费的时间,如代码所示,看起来secondAlgorithm比第一个算法花费的时间更少。结果看起来像
algorithm1 time taken until second equad found 105181
algorithm2 time taken until second equad found 63047
然而,在main()函数中,我调用这两个函数并测量每个函数所花费的时间,结果是
#include <iostream>
#include <random>
#include <chrono>
#include <fstream>
#include "Point.h"
bool isInside(Equads& eQuad, Point& p)
{
if(orientation(eQuad.extremePoints[0], eQuad.extremePoints[1], p) < 0)
{
return false;
}
else if(orientation(eQuad.extremePoints[1], eQuad.extremePoints[2], p) < 0)
{
return false;
}
else if(orientation(eQuad.extremePoints[2], eQuad.extremePoints[3], p) < 0)
{
return false;
}
else if(orientation(eQuad.extremePoints[3], eQuad.extremePoints[0], p) < 0)
{
return false;
}
else
{
return true;
}
}
void main()
{
std::chrono::high_resolution_clock::time_point start;
std::chrono::high_resolution_clock::time_point end;
start = std::chrono::high_resolution_clock::now();
firstAlgorithm(points);
end = std::chrono::high_resolution_clock::now();
std::cout << "compute time of firstAlgorithm (microseconds)" << chrono::duration_cast<std::chrono::microseconds>(end - start).count() << std::endl;
start = std::chrono::high_resolution_clock::now();
secondAlgorithm(points);
end = std::chrono::high_resolution_clock::now();
std::cout << "compute time of secondAlgorithm (microseconds)" << chrono::duration_cast<std::chrono::microseconds>(end - start).count() << std::endl;
}
compute time of firstAlgorithm (microseconds) : 107282
compute time of secondAlgorithm (microseconds) : 142401
为什么在main()函数中花费时间后,secondAlgorithm变得如此慢?
以下是第一种方式的代码。
vector<Point> firstAlgorithm(vector<Point>& originalPoint)
{
std::chrono::high_resolution_clock::time_point startTime;
std::chrono::high_resolution_clock::time_point endTime;
startTime = std::chrono::high_resolution_clock::now();
vector<Point> points = originalPoints;
PointSequence result;
Equads firstEquad; // Equads is array of points that store the four extreme points
findExtremePoints1(points, firstEquad);
Equads prev;
prev = firstEquad;
std::vector<Equads> eQuads;
Equads current;
int count = 0 ;
while(findExtremePoints2(points, prev, current) != false)
{
eQuads.push_back(current);
prev = current;
if(count == 0) break;
}
endTime = std::chrono::high_resolution_clock::now();
std::cout << std::endl << "algorithm1 time taken until second equad found " << std::chrono::duration_cast<std::chrono::microseconds>(endTime - startTime).count() << std::endl;
return result;
}
和findExtremePoints1和findExtremePoints2如下所示
void findExtremePoints1(vector<Point>& points, Equads& eQuad)
{
Point minX(points[0]),minY(points[0]),maxX(points[0]),maxY(points[0]);
for(size_t i = 1; i < points.size(); i++)
{
if(points[i].x < minX.x)
{
minX = points[i];
}
if(points[i].x > maxX.x)
{
maxX = points[i];
}
if(points[i].y < minY.y)
{
minY = points[i];
}
if(points[i].y > maxY.y)
{
maxY = points[i];
}
}
eQuad.extremePoints[0] = minX;
eQuad.extremePoints[1] = minY;
eQuad.extremePoints[2] = maxX;
eQuad.extremePoints[3] = maxY;
// erase the extreme points
points.erase(remove(points.begin(),points.end(), eQuad.extremePoints[0]), points.end());
points.erase(remove(points.begin(),points.end(), eQuad.extremePoints[1]), points.end());
points.erase(remove(points.begin(),points.end(), eQuad.extremePoints[2]), points.end());
points.erase(remove(points.begin(),points.end(), eQuad.extremePoints[3]), points.end());
}
// traverse the points and if any point is inside of previous equad(four extreme points)
//then delete it from points set and if not inside find next four extreme points.
bool findExtremePoints2(vector<Point> points, Equads& prevEquad, Equads& eQuad)
{
Point minX,minY,maxX,maxY;
bool prevFound = false;
std::vector<size_t> deletedVal;
for(size_t i = 0; i < points.size(); i++)
{
if(isInside(prevEquad, points[i]))
{
deletedVal.push_back(i);
}
else
{
if(prevFound)
{
if(points[i].x < minX.x)
{
minX = points[i];
}
if(points[i].x > maxX.x)
{
maxX = points[i];
}
if(points[i].y < minY.y)
{
minY = points[i];
}
if(points[i].y > maxY.y)
{
maxY = points[i];
}
}
else // not inside of the prev equad and the very first one. only meet this condition at very first time.
{
minX = points[i];
minY = points[i];
maxX = points[i];
maxY = points[i];
prevFound = true;
}
}
}
if (prevFound == false)
{
return false;
}
eQuad.extremePoints[0] = minX;
eQuad.extremePoints[1] = minY;
eQuad.extremePoints[2] = maxX;
eQuad.extremePoints[3] = maxY;
for(size_t i = deletedVal.size(); i-- > 0;)
{
points[deletedVal.at(i)] = points.back();
points.pop_back();
}
// erase the extreme points
points.erase(remove(points.begin(),points.end(), eQuad.extremePoints[0]), points.end());
points.erase(remove(points.begin(),points.end(), eQuad.extremePoints[1]), points.end());
points.erase(remove(points.begin(),points.end(), eQuad.extremePoints[2]), points.end());
points.erase(remove(points.begin(),points.end(), eQuad.extremePoints[3]), points.end());
return prevFound;
}
下面是第二种方式的代码。
vector<Point> secondAlgorithm(vector<Point>& points)
{
std::chrono::high_resolution_clock::time_point startTime;
std::chrono::high_resolution_clock::time_point endTime;
startTime = std::chrono::high_resolution_clock::now();
vector<Point> result;
std::vector<Equads> eQuads;
Equads firstEquad;
size_t sizeOfPoints = points.size();
std::forward_list<size_t> remainedPoints;
findExtremePointsAtFirst(points,firstEquad, sizeOfPoints);
discardInsidePointsAtFirst(points,firstEquad,remainedPoints,sizeOfPoints);
int count = 0 ;
while(sizeOfPoints > 0)
{
Equads equads;
findExtremePoints3(points, equads, remainedPoints, sizeOfPoints);
eQuads.push_back(equads);
if(count == 0 ) break;
}
endTime = std::chrono::high_resolution_clock::now();
std::cout << "algorithm2 time taken until second equad found " << std::chrono::duration_cast<std::chrono::microseconds>(endTime - startTime).count() << std::endl<< std::endl;
return result;
}
和findExtremePointsAtFirst,discardInsidePointsAtFirst和findExtremePoints3如下所示。
void findExtremePointsAtFirst(vector<Point>& points, Equads& eQuad, size_t& sizeOfPoints)
{
Point minX(points[0]),minY(points[0]),maxX(points[0]),maxY(points[0]);
for(size_t i = 1; i < sizeOfPoints; i++)
{
if(points[i].x < minX.x)
{
minX = points[i];
}
if(points[i].x > maxX.x)
{
maxX = points[i];
}
if(points[i].y < minY.y)
{
minY = points[i];
}
if(points[i].y > maxY.y)
{
maxY = points[i];
}
}
eQuad.extremePoints[0] = minX;
eQuad.extremePoints[1] = minY;
eQuad.extremePoints[2] = maxX;
eQuad.extremePoints[3] = maxY;
}
void discardInsidePointsAtFirst(vector<Point>& points, Equads& prevEquad, std::forward_list<size_t>& remainedPoints, size_t& sizeOfPoints)
{
size_t remainedPointsSize = 0;
for(size_t i = 0; i < points.size(); i++)
{
if(!isInside(prevEquad, points[i]))
{
remainedPoints.push_front(i+1);
remainedPointsSize++;
}
}
sizeOfPoints = remainedPointsSize;
}
void findExtremePoints3(vector<Point>& points, Equads& eQuad, std::forward_list<size_t>& remainedPoints, size_t& sizeOfPoints)
{
Point minX(points[remainedPoints.front()-1]);
Point minY = minX, maxX = minX , maxY = minX;
for(size_t i : remainedPoints)
{
i--;
if(points[i].x < minX.x)
{
minX = points[i];
}
if(points[i].x > maxX.x)
{
maxX = points[i];
}
if(points[i].y < minY.y)
{
minY = points[i];
}
if(points[i].y > maxY.y)
{
maxY = points[i];
}
}
eQuad.extremePoints[0] = minX;
eQuad.extremePoints[1] = minY;
eQuad.extremePoints[2] = maxX;
eQuad.extremePoints[3] = maxY;
}
FYI
// Point.h file
using CoordinateType = double;
struct Point
{
CoordinateType x;
CoordinateType y;
// to find the leftmost point
bool operator < (const Point& operand);
bool operator ==(const Point& operand) const;
Point& operator=(const Point& p);
friend std::ostream& operator <<(std::ostream& os, const Point& p);
bool isLower(const Point& p);
bool isHigher(const Point& p);
Point(CoordinateType x = -9999.0, CoordinateType y = -9999.0):x(x),y(y) {}
Point(const Point& p) : x(p.x), y(p.y) {}
};
using PointSequence = std::vector<Point>;
int orientation(const Point& p, const Point& q, const Point& r);
struct Equads
{
Point extremePoints[4]; // Xmin, Ymin, Xmax, Ymax order
Equads& operator=(const Equads& e);
};
Equads& Equads::operator=(const Equads& e)
{
std::copy(std::begin(e.extremePoints), std::end(e.extremePoints), std::begin(extremePoints));
std::copy(std::begin(e.subRegions), std::end(e.subRegions), std::begin(subRegions));
return *this;
}
// Point.cpp
#include "Point.h"
bool Point::operator <(const Point& operand)
{
if(this->x < operand.x)
return true;
else if(this->x == operand.x && this->y < operand.y)
return true;
else
return false;
}
bool Point::operator ==(const Point& operand) const
{
if((this->x == operand.x) && (this->y == operand.y))
return true;
else
return false;
}
Point& Point::operator=(const Point& p)
{
x = p.x;
y = p.y;
return *this;
}
std::ostream& operator<< (std::ostream& os, const Point& p)
{
os << p.x << " , " << p.y << std::endl;
return os;
}
bool Point::isLower(const Point& p)
{
if(this->y < p.y)
{
return true;
}
else if(this->y == p.y && this->x < p.x)
{
return true;
}
return false;
}
bool Point::isHigher(const Point& p)
{
if(this->y > p.y)
{
return true;
}
else if(this->y == p.y && this->x > p.x)
{
return true;
}
return false;
}
// to see if it turns clockwise or counterclockwise
int orientation(const Point& p, const Point& q, const Point& r)
{
double val = (q.x - p.x) * (r.y - p.y) - (q.y - p.y) * (r.x - p.x);
if (val == 0)
return 0; // colinear
return (val < 0) ? -1 : 1; // right or left
}
答案 0 :(得分:1)
任何局部变量在超出范围时都会被销毁(对于在循环或条件块内未声明的变量,当函数返回时会发生这种变量);如果其中任何一个是复杂类型(例如struct
/ class
个实例未隐藏在指针或引用之后),则会执行destructors,这可能需要额外的时间。
在这种情况下,您有Point
和Equads
个对象的向量,每个对象可能需要调用其析构函数。你的第一个算法是从它的points
向量中删除元素(增加函数内的总运行时间,但是当它退出时减少清理),而你的第二个算法没有(使它运行得更快但是更长时间清理)。