c语言凸包算法,基于C语言的凸包算法实现

基于C语言的凸包算法实现

非计算机专业,代码有些的不好的地方,大佬轻喷^ _ ^

根据要求,需要使用C语言实现凸包算法——Graham扫描法,本文将从算法理解、实现思路、遇到的问题及其解决方案三个方面来阐述实现过程。

算法理解

凸包算法Graham扫描法,在不考虑排序算法的时间复杂度情况下,算法核心程序的时间复杂度为 O ( n l o g n ) O(n log n)O(nlogn),其主要算法思想如下:

首先是预处理过程,获得一组随机点集,选取位于二维空间中左下角的点,即在纵坐标(y)最小情况下横坐标(x)为最小的点P 0 P_0P0​ 。以该点位极坐标原点计算其余各点的极角θ \thetaθ,并根据极角大小进行升序排序,若极角相同则按极径大小按升序排列。由此得到一组按照极角排序的点集 { P 0 , P 1 , . . . , P n } \left\{P_0,P_1,...,P_n\right\}{P0​,P1​,...,Pn​}(如下图所示)。

6c1555302777729326ca3efa0910d9ec.png

完成预处理之后即Graham算法的核心步骤,主要通过栈的方式来实现凸包点的计算。首先将P 0 , P 1 P_0,P_1P0​,P1​两点压栈,他们必然属于凸包上的点。然后进入迭代过程,以栈顶元素A [ t o p ] A[top]A[top]和次栈顶元素 A [ t o p − 1 ] A[top-1]A[top−1]构成的向量a ⃗ \vec{a}a为基准计算其与当前P k P_kPk​点与栈顶元素A [ t o p ] A[top]A[top]构成的向量b ⃗ \vec{b}b的叉积 ,若结果为正(零)则 b ⃗ \vec{b}b 位于 a ⃗ \vec{a}a 的逆时针方向(共线),P k P_kPk​进栈 ,若结果为负则 b ⃗ \vec{b}b 位于 a ⃗ \vec{a}a 的顺时针方向, A [ t o p ] A[top]A[top]出栈, P k P_kPk​进栈,直至扫描至最后一个点,将 P 0 P_0P0​ 再次进栈是凸包闭合。

由于要求顺时针输出凸包顶点,则将栈中元素从栈顶向栈底依次输出即可。

实现思路及过程

根据Graham扫描法的算法理解,将程序实现分为了随机点坐标初始化、极角计算及排序、Graham核心算法和结果输出四个模块共计8个函数进行编码实现。

结构体定义

// 点坐标

typedef struct POINT {

int x;

int y;

}Point;

坐标初始化

首先构造存储点坐标的结构体Point,该结构体中仅包含横坐标x和纵坐标y。根据要求需要随机生成100个点,使用宏定义点集大小(SIZE)为100。使用库下的rand()函数以当前系统时间为种子生成 0 ≤ x < 50 , 0 ≤ y < 50 0\le x<50,0\le y<500≤x<50,0≤y<50 的点,并依次存入大小为SIZE的Point的类型的一维数组中。

void InitPoint(Point* p) {

int i;

srand(time(0));

for (i = 0; i < SIZE; i++) {

(p + i)->x = (int)(rand() % 50);

(p + i)->y = (int)(rand() % 50);

}

}

极角计算及排序

首先选取点集中位于左下角的点,采用的方法为先找出纵坐标 最小的坐标点(集),然后在其中找出横坐标 最小的坐标点,记录该点位于原始点集的位置,将其与第一个点进行交换。接着使用库下的atan()函数计算各点的极角,并将其记录在double类型大小为SIZE的一维数组angle中,令极坐标原点的极角: a n g l e [ 0 ] = 0 angle[0] = 0angle[0]=0。使用冒泡排序算法对极角进行排序,同时改变点集中各点的顺序。在排序是要考虑当极角相同时按极径从小到大排序。

Graham核心算法

根据算法分析结果,定义一个Point类型的一维数组作为栈空间,定义栈顶定位变量top,用于标记栈顶元素在栈中的位置,定义临时变量temp_point用记录当前扫描到的坐标点,定义叉积计算函数,返回值为布尔类型。当叉积为非负时返回true,否则返回false。判断temp_point和栈顶元素,次顶元素三个点组成的两个向量的方向,若叉积返回值为正,则将temp_point进栈,否则将当前栈顶元素出栈,继续判断现在的栈顶元素和次顶元素与temp_point三个点的向量叉积……

得到包含所有凸包顶点的栈数组,最后将 点进栈形成封闭凸包,在形成封闭凸包前需要对 以及当前栈顶和次顶元素进行判断是否符合凸包结构,若符合则将 进栈,反之将当前栈顶元素出栈,重复判断步骤直至符合为止。

int myGraham(Point* p, Point* p_stack) {

int top = -1; //栈顶指针

int p_index = 0; //点索引

Point temp_point;

top++; p_stack[top] = p[0]; p_index++; //push

top++; p_stack[top] = p[1]; p_index++; //push

while (p_index < SIZE) {

temp_point = p[p_index];

if (X(p_stack[top - 1], p_stack[top], temp_point))

{

top++; p_stack[top] = temp_point;//push

}

else {

top--;//pop

continue;

}

p_index++;

}

while (TRUE) {

if (!X(p_stack[top - 1], p_stack[top], p[0])) {

top--;

}

else {

break;

}

}

top++; p_stack[top] = p[0];

return top;

}

结果输出

为了使结果更直观,定义了一个输出函数,能够输出凸包顶点坐标,并在二维坐标中,显示点。

运行结果

6c1555302777729326ca3efa0910d9ec.png

6c1555302777729326ca3efa0910d9ec.png

6c1555302777729326ca3efa0910d9ec.png

来源:oschina

链接:https://my.oschina.net/u/4355012/blog/4274913

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/429684.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VS Code 使用小技巧

所有插件查找地址&#xff08;https://marketplace.visualstudio.com/&#xff09; 编码快捷方式&#xff08;http://docs.emmet.io/cheat-sheet/&#xff09; 安装插件出现 错误unable to verify the first certificate &#xff08;无法确认第一证书&#xff09;   解决方…

android 怎么自定义任务栈,Android中的Activity详解--启动模式与任务栈

目录Activity生命周期任务栈启动模式Intent FlagtaskAffinity属性1.Activityactivity的简单介绍就不写了&#xff0c;作为最常用的四大组件之一&#xff0c;肯定都很熟悉其基本用法了。2.生命周期首先&#xff0c;是都很熟悉的一张图&#xff0c;即官方介绍的Activity生命周期图…

SQL Server--疑难杂症之坑爹的Windows故障转移群集

-- 估计是春节前最后一次写博客&#xff0c;也估计是本年值班最后一次踩雷&#xff0c;感叹下成也SQL SERVER&#xff0c;败也SQL SERVER。 -- 场景描述&#xff1a; 操作系统版本 &#xff1a;Windows Server 2012 数据中心版本 数据库版本 &#xff1a;SQL SERVER 2012 企业版…

android handle 阻塞,Android全面解析之Handler机制:常见问题汇总

主线程为什么不用初始化Looper&#xff1f;答&#xff1a;因为应用在启动的过程中就已经初始化主线程Looper了。每个java应用程序都是有一个main方法入口&#xff0c;Android是基于Java的程序也不例外。Android程序的入口在ActivityThread的main方法中&#xff1a;// 初始化主线…

gulp使用

gulp需要全局安装和当前目录都安装才能使用gulp命令 安装gulp插件 npm install gulp-rev gulp-rev-replace gulp-useref gulp-filter gulp-uglify gulp-csso --save-dev gulp-rev&#xff1a;给每个文件添加版本号&#xff0c;根据文件内容计算hash码&#xff0c;修改文件名&am…

android监听器作用,android - 监听器和接收器(Android)有什么区别?

例如&#xff0c;我需要一个BroadcastReceiver来获取这些事件:重新启动或关机屏幕开或关电池状态(电压&#xff0c;接通电源&#xff0c;温度)物理按钮按下(相机&#xff0c;媒体等)但是我需要监听器来获取以下事件:用于传感器事件(加速度&#xff0c;磁场&#xff0c;方向&…

UML中的6大关系(关联、依赖、聚合、组合、泛化、实现)

UML定义的关系主要有六种&#xff1a;依赖、类属、关联、实现、聚合和组合。这些类间关系的理解和使用是掌握和应用UML的关键&#xff0c;而也就是这几种关系&#xff0c;往往会让初学者迷惑。这里给出这六种主要UML关系的说明和类图描述&#xff0c;一看之下&#xff0c;清晰明…

android 相册 uri空,Android---相册getContentResolver().query结果为空指针

针对小米4手机上测试如下代码&#xff1a;Uri uri data.getData();String[] proj {MediaStore.Images.Media.DATA};//Cursor cursor managedQuery(uri, proj, null, null, null);Cursor cursor getContentResolver().query(uri, proj, null, null, null);cursor.moveToFirs…

用Spark学习FP Tree算法和PrefixSpan算法

在FP Tree算法原理总结和PrefixSpan算法原理总结中&#xff0c;我们对FP Tree和PrefixSpan这两种关联算法的原理做了总结&#xff0c;这里就从实践的角度介绍如何使用这两个算法。由于scikit-learn中没有关联算法的类库&#xff0c;而Spark MLlib有&#xff0c;本文的使用以Spa…

android os n9005,SM-N9005

hkSM-N9005ZKETELSM-N9005{"softwares":[{"description":"SAMSUNG Kies,PC Sync","fileName":"Kies3Setup.exe","fileModifiedDate":"2013年9月11日","fileVersion":"Kies 3.0(13091_39…

性能调优-硬盘方面,操作系统方面,文件系统方面

硬盘对数据库性能的影响 传统机械硬盘 当前大多数数据库使用的都是传统的机械硬盘。机械硬盘的技术目前已非常成熟&#xff0c;在服务器领域一般使用SAS或SATA接口的硬盘。服务器机械硬盘开始向小型化转型&#xff0c;目前已经有大量2.5寸的SAS机械硬盘。 机械硬盘有两个重要的…

chrome Android 80,Chrome OS 80将为Chromebook带来侧载Android应用的支持

如需体验这项功能&#xff0c;需在启动 Crostini 容器时加上一行特殊的命令 —— 从 Chromebook 命令行启动时&#xff0c;请加上 –enable-features ArcAdbSideloading 。最终&#xff0c;我们希望这回成为一项明示的标记(flags)功能。如变更日志所述&#xff0c;用户可通过托…

BZOJ4122 : [Baltic2015]File paths

对于在$o$点的某个询问&#xff0c;有两种情况&#xff1a; 情况1&#xff1a;走到任意一个点$x$然后超链接跳到$o$的某个祖先$y$再走到$o$。 枚举所有$y$看看是否存在$x$即可。 时间复杂度$O(nm)$。 情况2&#xff1a;走到$o$的某个祖先$x$&#xff0c;然后走到$x$子树内某个点…

android 日历仿IOS,基于Android week view仿小米和iphone日历效果

前言最近由于项目需求&#xff0c;要做一个仿小米日历的功能&#xff0c;下面显示一天的日程&#xff0c;header以周为单位进行滑动&#xff0c;github上找了很久也没有找到合适的&#xff0c;但找到一相近的开源项目Android-week-view&#xff0c;它不是我们项目所需要的效果&…

Deque - leetcode 【双端队列】

239. Sliding Window Maximum //大概思路是用双向队列保存数字的下标&#xff0c;遍历整个数组&#xff0c;如果此时队列的首元素是i - k的话&#xff0c;表示此时窗口向右移了一步&#xff0c;则移除队首元素。然后比较队尾元素和将要进来的值&#xff0c;如果小的话就都移除&…

android开源系统brvah,Android Jetpack之通用Adapter(Databinding+BRVAH)

之前发过一个databinding版的通用adapter&#xff0c;能实现一般需求&#xff0c;不过功能比较简陋&#xff0c;实际开发中大家更倾向于使用BRVAH等功能丰富的第三方框架。现在给出一个基于BRVAH的databinding版通用Adapter。BaseAdapterabstract class BaseAdapter(private va…

1、管理员登录中间件和注销

1、根据session去判断用户是否登录&#xff0c;登录后才可以进index首页&#xff0c;否则返回login页面&#xff0c;借助中间件 (1)修改路由 Route::group([middleware > [web,admin.login],prefix>admin,namespace>Admin], function () { //注册一个中间件admin.logi…

HTML阅读打开点击不了,如何让网页文章中的代码可以点击运行

在网页中运行代码HTML5学堂&#xff1a;很多代码网站当中&#xff0c;都会提供运行代码段功能&#xff0c;便于查看代码效果&#xff0c;那么这个是如何实现的呢&#xff1f;一起来看一下——如何在网页中运行代码。HTML5学堂-刘国利said&#xff1a;应该是在2013年的时候&…

angular-cli构建

angular-cli全称Command Line Interface 命令行界面 1使用命令 npm install -g angular-cli 安装angular-cli, 2安装完成后使用cli快速常见一个angular模板, 3ng serve启动项目 4在模板(seed/种子)的基础上进行修改 ############################## 在typescript中引用leanclou…

模仿块级作用域

模仿块级作用域 JavaScript中没有块级作用域&#xff0c;这意为着在块语句中定义的变量&#xff0c;实际上是包含在函数中而非语句中创建的。 下面的这个实例可以看出: function outputNumbers(count){for (var i0; i < count; i){alert(i);}alert(i); //count }outputNum…