凸包的形成(C++双向循环链表描述)

来源:互联网 发布:ui平面设计软件 编辑:程序博客网 时间:2024/06/05 10:16
#include<iostream>#include<fstream>//ifstream/ostream的头文件,文件流#include<sstream>//string流,istringstream,ostringstream#include "doublychain.h"#include "assert.h"//assert的头文件using namespace std;//凸包的形成void GeConvexHull(doublychain<pointInFlat>& S){       //任取两点画直线,检查其他点是否都在该直线上,若是则共线,求出两端点,反之则求出凸包。    const float PI = 3.1415926;chainNode<pointInFlat>*f, *s, *p;f = S.firstNode;s = f->next;float x1 = (f->element).x;float y1 = (f->element).y;float x2 = (s->element).x;float y2 = (s->element).y;float a = x2 - x1;float b = y2 - y1;float x = x1;float y = y1;p = s->next;while (a*(y - y1) - b*(x - x1) == 0 && p !=S.firstNode){x = (p->element).x;y = (p->element).y;p = p->next;}if (p == S.firstNode)//共线,有两种情况,垂直和不垂直,垂直时两端点的y值不一样,不垂直时只要求出横坐标的极值就得出两端点{pointInFlat min, max;chainNode<pointInFlat>*pt = S.firstNode;if (a == 0)//共线直线垂直于x轴{min.y = (pt->element).y;   //纵坐标最小的那个点max.y = (pt->element).y;    //纵坐标最大的那个点do                      //while (pt != NULL){if (min.y >= (pt->element).y)min.y = (pt->element).y;if (max.y <= (pt->element).y)max.y = (pt->element).y;pt = pt->next;} while (pt != S.firstNode);}else                   //共线直线没有垂直于x轴{min.x = (pt->element).x;   //纵坐标最小的那个点max.x = (pt->element).x;    //纵坐标最大的那个点do                          //while (pt != NULL){if (min.x >= (pt->element).x)min.x = (pt->element).x;if (max.x <= (pt->element).x)max.x = (pt->element).x;pt = pt->next;} while (pt != S.firstNode);}}else {   //S内的点不共线,形成凸包pointInFlat X;  //确定S内部的一个点XX.x = (x1 + x2 + x) / 3;X.y = (y1 + y2 + y) / 3;for (int k =0; k <2; ++k){//采用冒泡排序对S中的点进行排序chainNode<pointInFlat>*pr, *pd, *pb, *ps,*p;pr = S.lastNode;pd =S.firstNode;    //pd = NULL;            bool sorted = false;do{sorted = true;ps = pr->next;                         //由于X在计算机中的计算结果和实际有偏差,故实际相等的点会改变原来点的顺序,不过对结果没影响while (ps->next != pd)     //比较后面的元素{pb = ps->next;float xs = ps->element.x;float ys = ps->element.y;float xb = pb->element.x;float yb = pb->element.y;float lA_s= 0;float lA_b= 0;if (k == 0){ lA_s = sqrt(pow(xs - X.x, 2) + pow(ys - X.y, 2)); lA_b = sqrt(pow(xb - X.x, 2) + pow(yb - X.y, 2));//计算开始的两个点到X的距离,进行比较}else{ float txs = X.y - ys; float tys = xs - X.x;       lA_s = asin(tys / sqrt(txs*txs + tys*tys));           lA_s= lA_s*180/PI;     if (lA_s < 0 && txs>0)                           //角在第四象限,需要转化 lA_s += 360;      else if (txs<0)                                   //角在第二三象限,需要转化       lA_s=180 - lA_s;float txb = X.y - yb;float tyb = xb - X.x;      lA_b = asin(tyb / sqrt(txb*txb + tyb*tyb));      lA_b = lA_b*180/PI;       if (lA_b<0 && txb>0)      lA_b+=360;    else if (txb<0)lA_b= 180 - lA_b;}if (lA_s>lA_b)                                         //交换指针域,速度要比交换数据域快{pr->next = pb;pb->pre = pr;ps->next = pb->next;pb->next->pre = ps;pb->next = ps;ps->pre = pb;sorted = false;if (pr == S.lastNode)                               //在交换时要特别注意首和尾节点,首节点和尾节点参与交换后,要说明尾节点和头节点{S.firstNode = pb;pb->pre = S.lastNode;}if (pb == S.lastNode)                            {S.lastNode = ps;ps->next = S.firstNode;}}pr = pr->next;ps = pr->next;pd = S.firstNode;}pd = ps;pr = S.lastNode;} while (pr->next != pd && !sorted);}//删除非极点的点//首先找到y最小的点pointInFlat ymin;chainNode<pointInFlat>*p_ym,*deleteNode;//记录y最小的指针chainNode<pointInFlat>*px,*prx,*prrx;//px为当前点的指针,prx为逆时针第二个指针,prrx为第三个指针chainNode<pointInFlat>*pi = S.firstNode;ymin.y = (pi->element).y;p_ym = S.firstNode;do {if (ymin.y>(pi->element).y)p_ym= pi;pi = pi->next;} while (pi->next != S.firstNode);for (px = p_ym,prx=px->next; prx!=p_ym;)   //删除非极点的点,for循环的第一部分是起始值,第二部分是判断{prrx = prx->next;//如果x,rx,rrx的逆时针夹角小于或等于180度,则删除rx. 向量叉乘积结果可以判断是顺时针还是逆时针。这里要把向量做三维处理才可以auto ax = (prx->element).x - (px->element).x;auto ay = (prx->element).y - (px->element).y;    //建立向量aauto bx= (prrx->element).x - (prx->element).x;auto by = (prrx->element).y - (prx->element).y;    //建立向量bif (ax*by -bx*ay <=0)   //条件进行转化{deleteNode = prx;prx = px;px = prx->pre; //开始的两节点都后退delete deleteNode;prx->next = prrx;prrx->pre = prx;             //delete deleteNode;} px = prx; //如果节点方向是左转的,则继续前进。 prx = prrx; }for (chainNode<pointInFlat>*p = S.firstNode; p != S.lastNode; p = p->next)cout << (p->element).x << " " << (p->element).y << "   ";cout << (S.lastNode->element).x << " " << (S.lastNode->element).y << "  ";}}int main(){doublychain<pointInFlat>S;int i = 0;ifstream infile("coordinate.txt");   //把txt文件转换为输入流assert(infile.is_open());            //检查文件是否打开string str;                          //逐行读入的中间变量while (getline(infile, str))         //逐行读入{pointInFlat po;istringstream istr(str);         //将string分割为单个单词,相当于从string中读取数据istr>>po.x>>po.y;S.insert(i, po);++i;}GeConvexHull(S);return 0;}
测试结果:
txt输入坐标:
0  00  11 12  12  01 -11 01 3
输出坐标:
1 -1   2 0   2 1   1 3   0 1   0 0

原创粉丝点击