凸壳问题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 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