导航菜单
首页 >  算法期末考试最接近点对问题  > 二维最接近点对问题 代码+实验报告

二维最接近点对问题 代码+实验报告

1. 算法介绍

代码使用的算法思想为分治算法,即将一个大问题分割为若干个类似的、独立的子问题,随后递归地解决这些子问题,最终将子问题的解合并起来以解 决原始问题。此算法一般包含三个步骤:分解、解决、合并。

2. 代码说明

代码为 C 语言编写,共计定义了一个结构体和五个函数。下面对各个部分分 别进行介绍。

Point 结构体:成员为整型数据的 x 和 y,用于表示一个二维点的坐标;

Calc_distance(Point a,Point b)函数:计算并返回两个点的欧几里得距 离;

Swap(Point* a,Point* b)函数:交换两个结构体的内容;

Fmin(double a, double b)函数:模仿标准库中的 fmin 行为,返回两个给定值中的最小值; quicksort(Point arr[],int left,int right)函数:实现快速排序算法, 根据 x 坐标对点数组进行排序; closest_pair_distance(Point points[],int start,int end)函数:使用 分治方法递归地找出两点之间的最小距离。

进一步说明:

该函数接收一个点数组以及区间的开始索引和结束索引作为输入,随后分为三种情况:

(1) 开始索引大于等于结束索引:函数将返回一个值(此处设定为 1e9);

(2) 开始索引与结束索引之差为 1:函数将直接计算并返回这两个点之间 的距离;

(3) 其他情况:函数将计算中间索引(int mid = (end + start)/2),随后递归调用自身,分别计算左半部分和右半部分的最小距离,然后取 两者的最小值作为当前区间的最小距离。

在这之后,函数创建了一个 strip,用于存储距离中间线距离小于已知最小距离的点对。通过遍历点数组,将满足条件的点加入 strip 数组内。接着, 在 strip 内部,通过双循环遍历每对点,更新当前的最小距离为 strip 内部 点对的距离中的最小值,最后返回最小距离。

再说一下主函数:在主函数中,首先读取点的数量 n,随后通过 malloc 为这些点动态分配内存,并通过 for 循环逐一读取各个点的坐标。之后借由 quicksort 函数按照 x 坐标对这些点进行一个递归之外的排序,最后调用 closest_pair_distance 函数计算最近点对的距离并返回。

3. 算法分析

当输入点的数量逐渐增加时,如果不预先对点进行排序,可能会降低计算效 率并大大提高最近点对搜索和距离计算的时间复杂度。因此,对二维点进行 排序是必要的。

代码中使用的排序算法为快速排序。首先从待排序数组中选择一个元素作为基准值,随后进行分区:将数组中小于基准值的元素移到基准值的左边,将 大于基准值的元素移动到基准值的右边,而此时基准值的位置会被确定下来。 接着进行递归,对基准值左右两个子数组分别重复以上步骤,直到子数组的大小为 1 或 0,即子数组已经有序。经过计算,快速排序的时间复杂度为 O(n log n),n 是待排序数组的长度,最坏情况下为 O(n^2),但通常情况下表现良好。

对比另一种排序方法,冒泡排序,后者的时间复杂度最好情况下(数组已然有序)为 O(n),平均时间复杂度为 O(n^2)。通过图表可以很直观地感受到快速排序在数据量增多时的优势。

在计算最近点距离时,代码采用的是分治算法,期望时间复杂度为 O(n log n)。如果采用穷举法,即计算所有点对之间的距离并找出最小的距离,具体而言,对于 n 个点,穷举法需要计算大约 n*(n-1)/2 个点对的距离,则时间复杂度变为 O(n^2)。

下面是实际测算出的代码运行时间表格。

按理绘制出的曲线应是呈 nlogn 速率增长的。

4. 总结

在本次实验中,通过研究二维最接近点对距离问题,我深入理解了分治算法的 思想,并对其在实际问题中的应用有了更深入的认识。

首先,分治算法是一种非常重要且广泛应用的算法思想,它将一个大问题划分 为多个小问题,然后递归地解决这些小问题,并将它们的解合并起来得到最终的结果。在二维最接近点对距离问题中,我将问题划分为两个子问题,分别在左右两个子集中求解最接近点对距离,然后通过合并步骤来求解跨越两个子集 的最接近点对距离。

其次,分治算法的关键在于如何将问题划分为更小的子问题,以及如何将子问题的解合并起来。在本实验中,我采用了一种基于 x 坐标进行排序的方法来将 问题划分为两个子集,然后通过合并步骤来求解跨越两个子集的最接近点对距离。这种划分和合并的策略使得算法的时间复杂度能够达到 O(n log n),在实 际应用中具有很高的效率。

最后,通过本次实验,我不仅加深了对分治算法的理解,还学习到了如何将这种算法思想应用到解决实际问题中。同时,我也发现了分治算法在处理一些复 杂问题时可能存在的一些挑战,如如何进行合并步骤、如何处理边界情况等。 这些挑战需要我们进一步思考和研究,以提高算法的效率。

综上所述,通过本次实验,我对分治算法的思想有了更深入的理解,也掌握了如何将其应用到解决实际问题中的技巧与方法,这对我今后的算法设计与分析工作都具有重要的指导意义

5.源代码 #include #include #include #define _CRT_SECURE_NO_WARNINGStypedef struct {int x, y;} Point;// 计算两点之间的距离double calc_distance(Point a, Point b) {return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2));}void swap(Point * a, Point * b) {Point temp = *a;*a = *b;*b = temp;}double fmin(double a, double b) {if (a > b) return b;else return a;}void quickSort(Point arr[], int left, int right) {if (left < right) {int i = left, j = right;Point pivot = arr[left + (right - left) / 2]; // 选择中间点作为枢纽while (i pivot.x) // 在枢纽右侧找到第一个小于等于枢纽值的元素j--;if (i = end) {return 1e9; // 假设初始最小距离为1e9}else if (end - start == 1) {return calc_distance(points[start], points[end]);}int mid = (end + start) / 2;double left_min = closest_pair_distance(points, start, mid);double right_min = closest_pair_distance(points, mid + 1, end);double min_distance = fmin(left_min, right_min);int strip_size = 0;Point* strip = (Point*)malloc((end - start + 1) * sizeof(Point)); // 动态分配内存初始化 strip 数组for (int i = start; i

相关推荐: