算法设计与分析之用分治法解决凸包问题

凸包问题的分治思想

1.把给定点集中的点在横坐标方向上按照大小排序。如图1所示, p1 p 1 pn p n 必是凸多边形的两个顶点。
2.在上凸包点集合 S1 S 1 中找到一个距离直线最远的点 pmax p m a x ,如图2所示。显然直线段 p1 p 1 pmax p m a x 与直线段 pn p n pmax p m a x 把点集 S1 S 1 分成了3个集合。由凸包的性质可知 p1 p 1 pmax p m a x pn p n 三点围成的三角形中的点不可能作为凸包的顶点,所以只考虑直线 p1pmax p 1 p m a x 左边的点 S11 S 11 以及直线 pmaxpn p m a x p n 左边的点 S12 S 12 ,如图3所示。
3.递归求解得到凸多边形的边。
4.合并这些点即得所求凸包。

算法设计与分析之用分治法解决凸包问题_第1张图片

凸包问题的分治算法

void DealWithLeft(int first, int final, Point *array, Point *result)
{
    int max = 0, index = -1;
    int i = first;
    if (firstarray[final]射线左侧
    {
        for (i; iint x1 = array[first].x, y1 = array[first].y;
            int x2 = array[final].x, y2 = array[final].y;
            int x3 = array[i].x, y3 = array[i].y;

            int compute = x1*y2 + x3*y1 + x2*y3 - x3*y2 - x2*y1 - x1*y3;
            if (compute > max)
            {
                max = compute;
                index = i;
            }
        }
    }
    else
    {
        for (i; i >= 0; i--)//array[final]->array[first]射线左侧
        {
            int x1 = array[first].x, y1 = array[first].y;
            int x2 = array[final].x, y2 = array[final].y;
            int x3 = array[i].x, y3 = array[i].y;

            int compute = x1*y2 + x3*y1 + x2*y3 - x3*y2 - x2*y1 - x1*y3;
            if (compute > max)
            {
                max = compute;
                index = i;
            }
        }
    }

    if (index != -1)    //取到array[index](即最高点) ,这个点与array[final]、array[first]构成的三角形面积最大
    {
        Add(array, result, index);
        DealWithLeft(first, index, array, result);
        DealWithLeft(index, final, array, result);
    }
}

算法复杂度

快包的效率与快速排序的效率相同,平均情况下是 O(nlog2n) O ( n l o g 2 n ) ,最坏情况下是 O(n2) O ( n 2 )

源码

#include "stdafx.h"
#include

typedef struct {
    int x, y;
}Point;

int arrayLength = 0;    //数组长度

//初始化测试数据,返回一个数组
void InitialData(Point *array)
{
    FILE *fp = freopen("input.txt", "r", stdin);
    char ch;
    Point* currentPoint = array;
    for (int i = 0; ch != EOF; i++)
    {
        scanf_s("%d%d", &array[i].x, &array[i].y);
        ch = fgetc(fp);
        arrayLength++;
    }
    fclose(fp);
}

//交换位置
void swap(Point *array, int i, int j)
{
    if (iint x = 0, y = 0;
        x = array[i].x;
        y = array[i].y;
        array[i].x = array[j].x;
        array[i].y = array[j].y;
        array[j].x = x;
        array[j].y = y;
    }
}
//返回分裂位置
int Partition(Point *array, int l, int r)
{
    int p = l, i = l, j = r + 1;
    do
    {
        do
        {
            i++;
        } while (array[i].x<array[p].x);
        do
        {
            j--;
        } while (array[j].x>array[p].x);
        swap(array, i, j);
    } while (iarray, i, j);
    swap(array, p, j);
    return j;
}

//按x坐标的值从大到小排序,这里用的是快排
void Qsort(Point *array, int l, int r)
{
    int s = 0;
    if (larray, l, r); //找到分裂位置
        Qsort(array, l, s - 1);
        Qsort(array, s + 1, r);
    }
}
//打印数组
void Put(Point *array, int length)
{
    for (int i = 0; i"%d\t%d\n", array[i].x, array[i].y);
    }
    printf_s("\n");
}

int resultCount = 0;    //result[15]里面插入值的个数

//向result数组里面添加array数组首尾项
void Add(Point *array, Point *result)
{
    result[resultCount].x = array[0].x;
    result[resultCount++].y = array[0].y;

    result[resultCount].x = array[14].x;
    result[resultCount++].y = array[14].y;
}

//向result数组里面添加 array[i]
void Add(Point *array, Point *result, int i)
{
    result[resultCount].x = array[i].x;
    result[resultCount++].y = array[i].y;
}

//处理array[first]->array[final]射线左侧的点
void DealWithLeft(int first, int final, Point *array, Point *result)
{
    int max = 0, index = -1;
    int i = first;
    if (first//array[first]->array[final]射线左侧
    {
        for (i; iint x1 = array[first].x, y1 = array[first].y;
            int x2 = array[final].x, y2 = array[final].y;
            int x3 = array[i].x, y3 = array[i].y;

            int compute = x1*y2 + x3*y1 + x2*y3 - x3*y2 - x2*y1 - x1*y3;
            if (compute > max)
            {
                max = compute;
                index = i;
            }
        }
    }
    else
    {
        for (i; i >= 0; i--)//array[final]->array[first]射线左侧
        {
            int x1 = array[first].x, y1 = array[first].y;
            int x2 = array[final].x, y2 = array[final].y;
            int x3 = array[i].x, y3 = array[i].y;

            int compute = x1*y2 + x3*y1 + x2*y3 - x3*y2 - x2*y1 - x1*y3;
            if (compute > max)
            {
                max = compute;
                index = i;
            }
        }
    }
    if (index != -1)    //取到array[index](即最高点) ,这个点与array[final]、array[first]构成的三角形面积最大
    {
        Add(array, result, index);
        DealWithLeft(first, index, array, result);
        DealWithLeft(index, final, array, result);
    }
}
void GetResult(Point *array, Point *result)
{
    Add(array, result); //将首尾两个点并入result[15]

    DealWithLeft(0, 14, array, result); //处理array[0]->array[14]射线左边的点
    DealWithLeft(14, 0, array, result); //处理array[14]->array[0]射线右边的点
}

int _tmain(int argc, _TCHAR* argv[])
{
    Point array[15], result[15];

    //初始化数组数据
    InitialData(array);
    printf_s("输入数据:\n\n");
    Put(array, arrayLength);

    //给数组排序,按x从小到大
    Qsort(array, 0, arrayLength - 1);

    printf_s("排序后的数据:\n\n");
    Put(array, arrayLength);
    //获取result数组,存放所有结果顶点
    GetResult(array, result);

    printf_s("结果集:\n\n");
    Put(result, resultCount);
    getchar();

    return 0;
}

你可能感兴趣的:(算法设计与分析之用分治法解决凸包问题)