您的位置:首页 > 编程语言 > C语言/C++

【算法学习】快包算法

2016-06-04 15:06 288 查看
#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
#include <math.h>

坐标数据结构:
typedef struct
{
float x;
float y;
}Point;
typedef bool(*Func)(Point, Point, Point);

判断点test是否在a,b组成的直线的上方:
bool Upstair(Point a, Point b, Point test)
{
double k, d;
if (fabs(a.x - test.x) < 0.000001 && fabs(a.y - test.y) < 0.000001
|| fabs(b.x - test.x) < 0.000001 && fabs(b.y - test.y) < 0.000001)
return false;
/* 此时test点肯定不符合结果(联想在main函数寻找a,b点时的要求) */
if (fabs(b.x - a.x) < 0.000001)
return false;
k = (b.y - a.y) / (b.x - a.x);
d = a.y - k * a.x;
double ret = k*test.x - test.y + d;
if (ret < -0.000001)	//点在上方
return true;
else   //点在线上 和 点在线的下方
return false;
}
判断点test是否在a,b组成的直线的下方:
bool Downstair(Point a, Point b, Point test)
{
double k, d;
if (fabs(a.x - test.x) < 0.000001 && fabs(a.y - test.y) < 0.000001
|| fabs(b.x - test.x) < 0.000001 && fabs(b.y - test.y) < 0.000001)
return false;
/* 此时test点肯定不符合结果(联想在main函数寻找a,b点时的要求) */
if (fabs(b.x - a.x) < 0.000001)
return false;
k = (b.y - a.y) / (b.x - a.x);
d = a.y - k * a.x;
double ret = k*test.x - test.y + d;
if (ret > 0.000001)	//点在下方
return true;
else   //点在线上 和 点在线的上方
return false;
}

查找符合的点,递归函数:
void FindPoint(Point point[], int plen, Point a, Point b, Func func)
{
if (plen == 0)
return;
/* 找出 Pmax 点 */
Point pmax;
pmax.x = point[0].x;
pmax.y = point[0].y;
double k, d;
k = (b.y - a.y) / (b.x - a.x);
d = a.y - k * a.x;
double dist = fabs(k*pmax.x - pmax.y + d);
double newdist;
for (int i = 1; i < plen; ++i)
{
newdist = fabs(k*point[i].x - point[i].y + d);
if (newdist - dist > 0.000001)
{
pmax.x = point[i].x;
pmax.y = point[i].y;
}
else if (fabs(newdist - dist) < 0.000001)
{	//选择使角PmaxPaPb最大的点
double k_pmax = (pmax.y - a.y) / (pmax.x - a.x);
double k_point = (point[i].y - a.y) / (point[i].x - a.x);
if (fabs(k_point - k) - fabs(k_pmax - k) > 0.000001)
{
pmax.x = point[i].x;
pmax.y = point[i].y;
}
}
}
printf("Point(%f, %f)\n", pmax.x, pmax.y);

/* 找出各自符合满足 Pmax,Pa 和 Pmax,Pb 的点 */
Point *p1 = (Point *)malloc((plen / 2 + 1)*sizeof(Point));
Point *p2 = (Point *)malloc((plen / 2 + 1)*sizeof(Point));
int p1idx = 0, p2idx = 0;
for (int i = 0; i < plen; ++i)
{
if (func(pmax, a, point[i]))
{
p1[p1idx].x = point[i].x;
p1[p1idx].y = point[i].y;
p1idx++;
}
else if (func(pmax, b, point[i]))
{
p2[p2idx].x = point[i].x;
p2[p2idx].y = point[i].y;
p2idx++;
}
}
/* 递归寻找Pmax */
FindPoint(p1, p1idx, pmax, a, func);
FindPoint(p2, p2idx, pmax, b, func);

free(p1);
free(p2);

}主函数:
int _tmain(int argc, _TCHAR* argv[])
{
int number = 0;
while (number < 3)
{
printf("How much Point do you input(>=3):\n");
scanf("%d", &number);
}
printf("Please input Point:\n");

Point *p = (Point *)malloc(number * sizeof(Point));
for (int i = 0; i < number; ++i)
{
scanf("%f%f", &(p[i].x), &(p[i].y));
}

/* 找出两个顶点 */
Point a, b;
a.x = p[0].x;
a.y = p[0].y;
b.x = p[0].x;
b.y = p[0].y;
for (int i = 1; i < number; ++i)
{
if (a.x - p[i].x > 0.000001) //有比a更小的(横坐标)
{
a.x = p[i].x;
a.y = p[i].y;
}
else if (fabs(a.x - p[i].x) < 0.000001)
{ // 存在和a在同一竖直线上的点,此时应该选择最上或最下的点(这里选最上)
if (p[i].y - a.y > 0.000001)
{
a.x = p[i].x;
a.y = p[i].y;
}
}
if (b.x - p[i].x < -0.000001)
{
printf("b change\n");
b.x = p[i].x;
b.y = p[i].y;
}
else if (fabs(b.x - p[i].x) < 0.000001)
{ // 存在和b在同一竖直线上的点,此时应该选择最上或最下的点(这里选最下,和a对应,为了更可能的均分上包和下包点数)
if (p[i].y - a.y < -0.000001)
{
b.x = p[i].x;
b.y = p[i].y;
}
}
}
/* 所有点在一条竖直的线,则此时已是所求结果 */
if (fabs(a.x - b.x) < 0.000001)
{
printf("Point(%f, %f)\n", a.x, a.y);
printf("Point(%f, %f)\n", b.x, b.y);
system("pause");
return 0;
}

printf("Point(%f, %f)\n", a.x, a.y);
printf("Point(%f, %f)\n", b.x, b.y);
/* 划分点为两个集,即上包 和 下包*/
Point *p1 = (Point *)malloc((number / 2 + 1)*sizeof(Point));
Point *p2 = (Point *)malloc((number / 2 + 1)*sizeof(Point));
int p1idx = 0, p2idx = 0;
for (int i = 0; i < number; ++i)
{
if (Upstair(a, b, p[i]))
{
p1[p1idx].x = p[i].x;
p1[p1idx].y = p[i].y;
p1idx++;
}
else if (Downstair(a, b, p[i]))
{
p2[p2idx].x = p[i].x;
p2[p2idx].y = p[i].y;
p2idx++;
}
}
FindPoint(p1, p1idx, a, b, Upstair);
FindPoint(p2, p2idx, a, b, Downstair);

free(p);
free(p1);
free(p2);
system("pause");
_tmain(0, NULL);

return 0;


算法分析:

在输入数中分上包和下包时时间复杂度为O(n),两个递归函数的调用规模下降为n/2.

故可得T(n) = 2T(n/2) + n,递归函数遍历元素时间复杂度为n,然后同样道理递归, 最好的效率是刚好上包和下包元素相等或差一的情况。

由T(n) = 2T(n/2) + n ,得T(2^k) = 2T(2^k-1) + 2^k

T(2^k) = 2(2T(2^k-2) + 2^k-1) + 2^k

= 2^2T(2^k-2) + 2*2^k

= 2^kT(1) + k*2^k

由T(1) = 1,k = logn

T(n) = n + logn*n

所以,时间复杂度是nlogn.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法 c语言