凸壳问题

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

1

凸壳问题

凸壳问题的格雷厄姆(Graham )扫描法 一、凸壳问题

1、凸壳的定义

定义:令S 是平面上的一个点集,封闭S 中所有顶点的最小凸多边形,称为S 的凸壳,表示为)(S CH 。)(S CH 上的顶点,有时也叫做S 的极点。 2、凸壳问题

给定平面上n 个点的集合S ,求S 的凸壳)(S CH 。

二、思想方法

1、在平面点集S 中,寻找Y 坐标最小的点。把它称为0p 。

2、以0p 为源点,对所有点的坐标进行变换。

3、对变换后的所有点,以0p 为源点,计算它们的极坐标幅角。

4、以幅角的非降顺序来排序}{0p S -中的点,令排序过的点为

},,,{121-=n p p p T ,其中,1p 和1-n p 分别与0p 构成最小与最大的幅

角。

5、把点集T 中的元素,作为事件调度点进行扫描。

6、用堆栈CS 作为扫描过程中局部构成的半封闭凸多边形,把它

2

作为扫描线状态维护。7、堆栈初始化为},{01p p CS n -=,其中,0p 为栈顶元素。

8、按极坐标的幅角,从1p 开始,到1-n p 为止进行扫描。 9、扫描处理:

假定,在某一个时刻,堆栈内容为:

},,,,,{01k j i n p p p p p CS -=

其中,k p 为栈顶元素,则栈中元素按顺序构成半封闭的凸多边形。

令l p 是正在扫描的点,如果由j p 、k p 、l p 所构成的路径是左转的,则由j p 、k p 、l p 形成的边是凸边,把l k p p 作为凸多边形中的边加入进来,把l p 压入栈顶,把扫描线移到下一点;

如果由j p 、k p 、l p 所构成的路径是右转的,则由j p 、k p 、l p 形成的边是凹边,k p 不是凸壳的极点。把k p 弹出栈顶,扫描线仍然停留在l p 上。

在下一轮处理中,将由i p 、j p 、l p 进行判断和作出处理。

3

格雷厄姆扫描法的实现 一、算法步骤:

1. 求平面点集S 中Y 坐标最小的点0p ;

2. 以0p 为源点,变换}{0p S -中所有点的坐标;

3. 以0p 为源点,计算}{0p S -中所有点的幅角;

4. 以幅角的非降顺序排序}{0p S -中所有的点,令事件调度点

},,,{121-=n p p p T 是排序过的数组;

5. 初始化堆栈:令1]0[-=n p CS ,0]1[p CS =;令堆栈指针1=sp ,事件调度点数组T 的下标0=k ;

6. 如果1-

7. 按(11.1.7)式计算]1[-sp CS ,][sp CS ,][k T 所构成的三角区符

号D ,若0≥D ,1+=sp sp ,][][k T sp CS =,1+=k k ;转6;否则,

1-=sp sp ;转6; 二、数据结构:

typedef struct {

float x; /* X 坐标 */ float y; /* Y 坐标 */ float ang; /* 极坐标的幅角 */ } SPOINT;

POINT S[n]; /* 平面点集 */

SPOINT T[n]; /* 按幅角的非降顺序排序的平面点集 */

POINT CS[n]; /* 构成凸壳的点集 */

三、算法的实现:

算法11.2 求平面点集的凸壳

输入:平面点集S[],顶点个数n

输出:构成凸壳的极点CS[];极点个数sp

1. void convex_hull(POINT S[],POINT CS[],int

n,int &sp)

2. {

3. int i,k;

4. float D;

5. SPOINT T[n];

6. for (i=1;i

/* S中Y坐标最小的点于S[0]*/

7.if

(S[i].y

[0].x)))

4

8. swap(S[i],S[0]);

9. for (i=1;i

/* 以S[0] 为源点,变换S[i]的坐标于T[i] */

10. T[i-1].x = S[i].x – S[0].x;

T[i].y = S[i].y – S[0].y;

11. T[i-1].ang = atan(T[i-1].y,T[i-1].x); /* 求T[i]的幅角 */

12. }

13. sort(T,n-1);

/* 按T[i]幅角的非降顺序排序T[i] */

14. CS[0].x = T[n-2].x; CS[0].y = T[n-2].y;

15. CS[1].x = 0; CS[1].y = 0; sp = 1; k = 0;

16. while (k

/* 求栈顶两点及扫描线上一点所构成的三角区符号 */ 17. D = CS[sp-1].x*CS[sp].y + CS[sp].x*T[k].y + T[k].x*CS[sp-1].y

18. - CS[sp-1].y*CS[sp].x - CS[sp].y*T[k].x - T[k].y*CS[sp-1].x;

19. if (D>=0)

5

20. CS[++sp] = T[k++];

/* 若D≥0,T[k]压入栈顶,扫描线前移一点 */

21. else sp--; /* 否则,弹出栈顶元素 */

22. }

23. }

四、复杂性分析

1、数据复杂性:

第6~8行及9~12行,各需)

Θ时间;

(n

第13行的排序操作,需)

O时间;

n

log

(n

第16~22行的while循环,需)

Θ时间。

(n

因此,算法的时间复杂性是)

O。

n

log

(n

2、空间复杂性:

用于输入的平面点集、用于输出的凸壳极点需要)

Θ空间

(n 事件调度点数组,需要)

(n

Θ空间。

6

相关文档
最新文档