问题定义
一个点集 Σ \Sigma Σ的凸包是一个面积最小的凸多边形 P P P,满足点集中每个节点都在P的边界或者P的内部。
显然,凸包中每个顶点都是点集中的点。
主要方法
- 增量法(Incremental method),对点集进行从左到右排序,在第 i i i步中,根据前 i i i个节点形成是的凸包对第i个节点进行考察,是否加入p中。时间复杂度为 O ( n lg n ) O(n\lg n ) O(nlgn)
- 分治法,将点集分为最左边 n 2 \frac{n}{2} 2n个节点和最右边 n 2 \frac{n}{2} 2n节点,分别对这两部分进行递归计算。然后使用一种 O ( n ) O(n) O(n)的方法进行合并。 T ( n ) = 2 T ( n 2 ) + O ( n ) T(n) = 2T(\frac{n}{2}) + O(n) T(n)=2T(2n)+O(n)可以得到 T ( n ) = O ( n lg n ) T(n) = O(n\lg n) T(n)=O(nlgn)
- 剪枝搜索。
- 旋转扫除法,下面介绍的两种算法都是采用的该种方法。该方法通过类似旋转的过程,每次逐步完成凸包的构建。
Graham扫描法
它是按照以下流程进行的:
- 选择纵坐标最小的节点作为基准点 p 0 p_0 p0(如果存在多个则选择横坐标最小的点)
- 根据 p 0 p_0 p0对剩下的所有节点按照和 p 0 p_0 p0的极角进行排序。
- 将 p 0 , 和 排 序 后 的 p 1 , p 2 p_0,和排序后的p_1,p_2 p0,和排序后的p1,p2加入一个栈内。
- 考察第 i i i个节点 p i p_i pi,如果该节点和栈中的栈顶 l 0 l_0 l0,栈次顶 l 1 l_1 l1构成一个左转,那么将 p i p_i pi加入栈中,否则删除节点 l 0 l_0 l0,然后重复操作4,直到满足前一条件,或者栈中元素少于2.
- 程序结束,栈中元素即是凸包的逆时针序列。
Javis步进法
- 该算法的主要思路即每次寻找极角最小的点作为凸包。
- 寻找和Graham一样的 p 0 p_0 p0点。
- 以该点为基准点,寻找极角最小的点,并以该节点为新的基准点重复步骤2.
- 如果步骤2发现的新的基准点为 p 0 p_0 p0则结束循环。步骤2中发现的基准点即为凸包。
==对于极角的比较,以及是否左转用到的都是点的叉乘,参见点的叉乘
备注:文中所有图片出自《算法导论》