算法复杂度最低界限LowBound
算法求解复杂度是否存在一个最低界限,有时候想尽一切办法优化一个算法,去优化其复杂度,比如
清华计算几何-ConvexHull(凸包)-求极点InTriangle/ToLeft Test-CSDN博客
清华计算几何-ConvexHull(凸包)-求极边_计算几何中的toleft测试-CSDN博客
清华计算几何-ConvexHull(凸包)-JarivsMarch-CSDN博客
算法复杂度依次到: O(n4), O(n3), O(n2)
一直优化下去能最低到哪个复杂度,有时候不好直接估算出。有个比较好的办法是从经典算法(比如排序)中,找到此算法和经典算法的等价转换。如果此算法和经典算法等价,则此算法的LowBound也是经典算法的LowBound。
算法等价转换
算法等价转换就是: 假设A为经典算法, 已经知道其算法复杂度。存在另外一个未知算法复杂度的算法B,如今要估算算法B的lowBond. 如果A算法的输入经过O(n)以内复杂度转换算法变为B算法输入,B算法计算的输出能在O(n)复杂度以内转换为A算法的输入,则称A算法和B算法等价。
估算ConvexHull算法的LowBound
从前面可以隐隐看出点集求解ConvexHull的流程和排序类似, 建立起排序和凸包的点集合之间O(n)的转换关系(点输入和点输出),排序的算法Lowbound就是凸包算法的Lowbound。
排序的LowBound是O(nlogn), 而等价下凸包算法也是O(nlogn)
凸包算法-GrahamScan
GrahamScan算法流程
Presorting(预排序)
[1]找到LowertToLeft点P
[2]找到和P点相连最右边的点(逆时针CCW)
Scan(扫描)
GrahamScan算法Backtrack执行案例
GrahamScan算法代码实现
算法核心代码
#include <iostream>
#include <vector>
#include <stack>
#include <list>
#include <algorithm>#include "BasicCompute.h"using namespace std;template<typename type>
class CustomStack
{
private:vector<type> datas;public:CustomStack(){}void Push(const type& value){datas.push_back(value);}type Pop(){int num = GetNum();if (num == 0)throw "size is zero, do not allow pop";int value = datas[num - 1];datas.pop_back();return value;}int GetNum(){return datas.size();}type GetTopValue(int topIndex = 0){return datas[GetNum() - topIndex - 1];}void GetVectorData(vector<type>& outDatas){outDatas = datas;}
};void GrahamScan_GetConvexPointSet(const vector<Point>& inPoints, vector<int>& convecHullPointIndexs)
{if (inPoints.size() <= 3)return;convecHullPointIndexs.empty();int ltfIndex = FindLowestThenLeftmost(inPoints);// quick sort by to leftvector<int> tArray;for (int index = 0; index < inPoints.size(); index++){if (index != ltfIndex)tArray.push_back(index);}auto CompareFunc = [&](int a, int b){return IsLeft(inPoints[ltfIndex], inPoints[a], inPoints[b]);};sort(tArray.begin(), tArray.end(), CompareFunc);// init stack s and stack tCustomStack<int> s;s.Push(ltfIndex);s.Push(tArray[0]);CustomStack<int> t;for (int index = tArray.size() - 1; index >= 1; index--){t.Push(tArray[index]);}while (t.GetNum() != 0){int sTopIndex = s.GetTopValue(0);int sTopSecondIndex = s.GetTopValue(1);int tTopIndex = t.GetTopValue(0);if (IsLeft(inPoints[sTopSecondIndex], inPoints[sTopIndex], inPoints[tTopIndex])){s.Push(t.Pop());}else{s.Pop();}}s.GetVectorData(convecHullPointIndexs);
}
测试代码
#include <iostream>
#include <vector>
#include "ExtremityEdgeConvex.h"
#include "JarvisMarch.h"
#include "GrahamScan.h"using namespace std;int main()
{std::cout << "Hello World!\n";// point set contructvector<Point> inPoints ={{0, 0},{-1, -1},{5, 2},{4, 5},{3, 3},{-1, 3},{2, 2},{-3, 2},};vector<int> convecHullPointIndexs;GrahamScan_GetConvexPointSet(inPoints, convecHullPointIndexs);for (int index = 0; index < convecHullPointIndexs.size(); index++){int pointIndex = convecHullPointIndexs[index];printf("(%f, %f)\n", inPoints[pointIndex].x, inPoints[pointIndex].y);}
}
测试结果
GrahamScan算法复杂度
PreProcesing:LTL复杂度O(n), Presorting是快排O(nlogn)
San扫描: Scan经过的路径是一个平面图(PlanarGraph), N个顶点的平面图至多拥有3N条边,也就是San算法复杂度不可能超过3N。也就是算法复杂度为O(n).
综上GrahamScan算法复杂度为O(nlogn)。
参考资料
[1]清华计算几何 P31-P48