#include #include #include #include #include #include #include "kdTree.h" using namespace std; bool cmp1(const coordinate& a, const coordinate& b) { return a.x > b.x; } bool cmp2(const coordinate& a, const coordinate& b) { return a.y > b.y; } bool cmp3(const coordinate& a, const coordinate& b) { return a.z > b.z; } bool equal(const coordinate& a, const coordinate& b) { return (a.x == b.x && a.y == b.y && a.z == b.z); } void ChooseSplit(coordinate exm_set[], int size, UL &split, coordinate &SplitChoice) { /*compute the variance on every dimension. Set split as the dismension that have the biggest variance. Then choose the instance which is the median on this split dimension.*/ /*compute variance on the x,y dimension. DX=EX^2-(EX)^2*/ double tmp1, tmp2; tmp1 = tmp2 = 0; for (int i = 0; i < size; ++i) { tmp1 += 1.0 / (double)size * exm_set[i].x * exm_set[i].x; tmp2 += 1.0 / (double)size * exm_set[i].x; } double v1 = tmp1 - tmp2 * tmp2; //compute variance on the x dimension ¼ÆËãx·½Ïò·½²î tmp1 = tmp2 = 0; for (int i = 0; i < size; ++i) { tmp1 += 1.0 / (double)size * exm_set[i].y * exm_set[i].y; tmp2 += 1.0 / (double)size * exm_set[i].y; } double v2 = tmp1 - tmp2 * tmp2; //compute variance on the y dimension ¼ÆËãy·½Ïò·½²î tmp1 = tmp2 = 0; for (int i = 0; i < size; ++i) { tmp1 += 1.0 / (double)size * exm_set[i].z * exm_set[i].z; tmp2 += 1.0 / (double)size * exm_set[i].z; } double v3 = tmp1 - tmp2 * tmp2; //compute variance on the z dimension ¼ÆËãz·½Ïò·½²î //split = v1 > v2 ? 0 : 1; //set the split dimension if (v1 >= v2 && v1 >= v3) { split = 0; std::nth_element(exm_set, exm_set + size / 2, exm_set + size, cmp1); } else if (v2 >= v1 && v2 >= v3) { split = 1; std::nth_element(exm_set, exm_set + size / 2, exm_set + size, cmp2); } else { split = 2; std::nth_element(exm_set, exm_set + size / 2, exm_set + size, cmp3); } //set the split point value SplitChoice.x = exm_set[size / 2 ].x; SplitChoice.y = exm_set[size / 2 ].y; SplitChoice.z = exm_set[size / 2 ].z; } TreeNode* build_kdtree(coordinate exm_set[], int size, TreeNode* T) { //call function ChooseSplit to choose the split dimension and split point if (size == 0) { return nullptr; } else { UL split; coordinate dom_elt; ChooseSplit(exm_set, size, split, dom_elt); coordinate *exm_set_right = new coordinate[size * 9 / 16 + 10]; coordinate *exm_set_left = new coordinate[size * 9 / 16 + 10]; int size_left, size_right; size_left = size_right = 0; switch (split) { case 0: for (UL i = 0; i < size; ++i) { if (!equal(exm_set[i], dom_elt) && exm_set[i].x <= dom_elt.x) { exm_set_left[size_left].x = exm_set[i].x; exm_set_left[size_left].y = exm_set[i].y; exm_set_left[size_left].z = exm_set[i].z; size_left++; } else if (!equal(exm_set[i], dom_elt) && exm_set[i].x > dom_elt.x) { exm_set_right[size_right].x = exm_set[i].x; exm_set_right[size_right].y = exm_set[i].y; exm_set_right[size_right].z = exm_set[i].z; size_right++; } } break; case 1: for (UL i = 0; i < size; ++i) { if (!equal(exm_set[i], dom_elt) && exm_set[i].y <= dom_elt.y) { exm_set_left[size_left].x = exm_set[i].x; exm_set_left[size_left].y = exm_set[i].y; exm_set_left[size_left].z = exm_set[i].z; size_left++; } else if (!equal(exm_set[i], dom_elt) && exm_set[i].y > dom_elt.y) { exm_set_right[size_right].x = exm_set[i].x; exm_set_right[size_right].y = exm_set[i].y; exm_set_right[size_right].z = exm_set[i].z; size_right++; } } break; default: for (UL i = 0; i < size; ++i) { if (!equal(exm_set[i], dom_elt) && exm_set[i].z <= dom_elt.z) { exm_set_left[size_left].x = exm_set[i].x; exm_set_left[size_left].y = exm_set[i].y; exm_set_left[size_left].z = exm_set[i].z; size_left++; } else if (!equal(exm_set[i], dom_elt) && exm_set[i].z > dom_elt.z) { exm_set_right[size_right].x = exm_set[i].x; exm_set_right[size_right].y = exm_set[i].y; exm_set_right[size_right].z = exm_set[i].z; size_right++; } } break; } T = new TreeNode; T->dom_elt.x = dom_elt.x; T->dom_elt.y = dom_elt.y; T->dom_elt.z = dom_elt.z; T->split = split; T->left = build_kdtree(exm_set_left, size_left, T->left); T->right = build_kdtree(exm_set_right, size_right, T->right); delete[] exm_set_left; delete[] exm_set_right; return T; } } double Distance(coordinate a, coordinate b) { double tmp = (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) + (a.z - b.z) * (a.z - b.z); return sqrt(tmp); } void searchNearest(TreeNode * Kd, coordinate target, coordinate &nearestpoint, double & distance) { //1. Èç¹ûKdÊǿյģ¬ÔòÉèdistΪÎÞÇî´ó·µ»Ø //2. ÏòÏÂËÑË÷Ö±µ½Ò¶×Ó½áµã stack search_path; TreeNode* pSearch = Kd; coordinate nearest; double dist; while (pSearch != nullptr) { //pSearch¼ÓÈëµ½search_pathÖÐ; search_path.push(pSearch); switch (pSearch->split) { case 0: if (target.x <= pSearch->dom_elt.x) /* Èç¹ûСÓھͽøÈë×ó×ÓÊ÷ */ { pSearch = pSearch->left; } else { pSearch = pSearch->right; } break; case 1: if (target.y <= pSearch->dom_elt.y) /* Èç¹ûСÓھͽøÈë×ó×ÓÊ÷ */ { pSearch = pSearch->left; } else { pSearch = pSearch->right; } break; default: if (target.z <= pSearch->dom_elt.z) /* Èç¹ûСÓھͽøÈë×ó×ÓÊ÷ */ { pSearch = pSearch->left; } else { pSearch = pSearch->right; } break; } } //È¡³ösearch_path×îºóÒ»¸ö¸³¸ønearest nearest.x = search_path.top()->dom_elt.x; nearest.y = search_path.top()->dom_elt.y; nearest.z = search_path.top()->dom_elt.z; search_path.pop(); dist = Distance(nearest, target); //3. »ØËÝËÑË÷·¾¶ TreeNode* pBack; while (!search_path.empty()) { //È¡³ösearch_path×îºóÒ»¸ö½áµã¸³¸øpBack pBack = search_path.top(); search_path.pop(); if (pBack->left == nullptr && pBack->right == nullptr) /* Èç¹ûpBackΪҶ×Ó½áµã */ { if (Distance(nearest, target) > Distance(pBack->dom_elt, target)) { nearest = pBack->dom_elt; dist = Distance(pBack->dom_elt, target); } } else { UL s = pBack->split; switch (s) { case 0: if (fabs(pBack->dom_elt.x - target.x) < dist) /* Èç¹ûÒÔtargetΪÖÐÐĵÄÔ²£¨Çò»ò³¬Çò£©£¬°ë¾¶ÎªdistµÄÔ²Óë·Ö¸î³¬Æ½ÃæÏཻ£¬ ÄÇô¾ÍÒªÌøµ½ÁíÒ»±ßµÄ×Ó¿Õ¼äÈ¥ËÑË÷ */ { if (Distance(nearest, target) > Distance(pBack->dom_elt, target)) { nearest = pBack->dom_elt; dist = Distance(pBack->dom_elt, target); } if (target.x <= pBack->dom_elt.x) /* Èç¹ûtargetλÓÚpBackµÄ×ó×ӿռ䣬ÄÇô¾ÍÒªÌøµ½ÓÒ×Ó¿Õ¼äÈ¥ËÑË÷ */ pSearch = pBack->right; else pSearch = pBack->left; /* Èç¹ûtargetλÓÚpBackµÄÓÒ×ӿռ䣬ÄÇô¾ÍÒªÌøµ½×ó×Ó¿Õ¼äÈ¥ËÑË÷ */ if (pSearch != nullptr) //pSearch¼ÓÈëµ½search_pathÖÐ search_path.push(pSearch); } break; case 1: if (fabs(pBack->dom_elt.y - target.y) < dist) /* Èç¹ûÒÔtargetΪÖÐÐĵÄÔ²£¨Çò»ò³¬Çò£©£¬°ë¾¶ÎªdistµÄÔ²Óë·Ö¸î³¬Æ½ÃæÏཻ£¬ ÄÇô¾ÍÒªÌøµ½ÁíÒ»±ßµÄ×Ó¿Õ¼äÈ¥ËÑË÷ */ { if (Distance(nearest, target) > Distance(pBack->dom_elt, target)) { nearest = pBack->dom_elt; dist = Distance(pBack->dom_elt, target); } if (target.y <= pBack->dom_elt.y) /* Èç¹ûtargetλÓÚpBackµÄ×ó×ӿռ䣬ÄÇô¾ÍÒªÌøµ½ÓÒ×Ó¿Õ¼äÈ¥ËÑË÷ */ pSearch = pBack->right; else pSearch = pBack->left; /* Èç¹ûtargetλÓÚpBackµÄÓÒ×ӿռ䣬ÄÇô¾ÍÒªÌøµ½×ó×Ó¿Õ¼äÈ¥ËÑË÷ */ if (pSearch != nullptr) // pSearch¼ÓÈëµ½search_pathÖÐ search_path.push(pSearch); } break; default: if (fabs(pBack->dom_elt.z - target.z) < dist) /* Èç¹ûÒÔtargetΪÖÐÐĵÄÔ²£¨Çò»ò³¬Çò£©£¬°ë¾¶ÎªdistµÄÔ²Óë·Ö¸î³¬Æ½ÃæÏཻ£¬ ÄÇô¾ÍÒªÌøµ½ÁíÒ»±ßµÄ×Ó¿Õ¼äÈ¥ËÑË÷ */ { if (Distance(nearest, target) > Distance(pBack->dom_elt, target)) { nearest = pBack->dom_elt; dist = Distance(pBack->dom_elt, target); } if (target.z <= pBack->dom_elt.z) /* Èç¹ûtargetλÓÚpBackµÄ×ó×ӿռ䣬ÄÇô¾ÍÒªÌøµ½ÓÒ×Ó¿Õ¼äÈ¥ËÑË÷ */ pSearch = pBack->right; else pSearch = pBack->left; /* Èç¹ûtargetλÓÚpBackµÄÓÒ×ӿռ䣬ÄÇô¾ÍÒªÌøµ½×ó×Ó¿Õ¼äÈ¥ËÑË÷ */ if (pSearch != nullptr) // pSearch¼ÓÈëµ½search_pathÖÐ search_path.push(pSearch); } break; } } } nearestpoint.x = nearest.x; nearestpoint.y = nearest.y; nearestpoint.z = nearest.z; distance = dist; } void searchNearest(const TreeElement* treeArray,int size, coordinate target, coordinate &nearestpoint, double & distance) { stack search_path; int index = 0; TreeElement pSearch = treeArray[index]; coordinate nearest; double dist; while (!pSearch.isEmpty) { search_path.push(index); if ((2 * index + 1) >= size) { break; } switch (pSearch.split) { case 0: if (target.x <= pSearch.dom_elt.x) /* Èç¹ûСÓھͽøÈë×ó×ÓÊ÷ */ { index = 2 * index + 1; pSearch = treeArray[index]; } else { index = 2 * index + 2; pSearch = treeArray[index]; } break; case 1: if (target.y <= pSearch.dom_elt.y) /* Èç¹ûСÓھͽøÈë×ó×ÓÊ÷ */ { index = 2 * index + 1; pSearch = treeArray[index]; } else { index = 2 * index + 2; pSearch = treeArray[index]; } break; default: if (target.z <= pSearch.dom_elt.z) /* Èç¹ûСÓھͽøÈë×ó×ÓÊ÷ */ { index = 2 * index + 1; pSearch = treeArray[index]; } else { index = 2 * index + 2; pSearch = treeArray[index]; } break; } } //È¡³ösearch_path×îºóÒ»¸ö¸³¸ønearest index = search_path.top(); nearest.x = treeArray[index].dom_elt.x; nearest.y = treeArray[index].dom_elt.y; nearest.z = treeArray[index].dom_elt.z; search_path.pop(); dist = Distance(nearest, target); //3. »ØËÝËÑË÷·¾¶ TreeElement pBack; while (!search_path.empty()) { //È¡³ösearch_path×îºóÒ»¸ö½áµã¸³¸øpBack index = search_path.top(); pBack = treeArray[index]; search_path.pop(); if ((2 * index + 1) >= size) /* Èç¹ûpBackΪҶ×Ó½áµã */ { if (Distance(nearest, target) > Distance(pBack.dom_elt, target)) { nearest = pBack.dom_elt; dist = Distance(pBack.dom_elt, target); } } else if (treeArray[2 * index + 1].isEmpty == true && treeArray[2 * index + 2].isEmpty == true) /* Èç¹ûpBackΪҶ×Ó½áµã */ { if (Distance(nearest, target) > Distance(pBack.dom_elt, target)) { nearest = pBack.dom_elt; dist = Distance(pBack.dom_elt, target); } } else { UL s = pBack.split; switch (s) { case 0: if (fabs(pBack.dom_elt.x - target.x) < dist) /* Èç¹ûÒÔtargetΪÖÐÐĵÄÔ²£¨Çò»ò³¬Çò£©£¬°ë¾¶ÎªdistµÄÔ²Óë·Ö¸î³¬Æ½ÃæÏཻ£¬ ÄÇô¾ÍÒªÌøµ½ÁíÒ»±ßµÄ×Ó¿Õ¼äÈ¥ËÑË÷ */ { if (Distance(nearest, target) > Distance(pBack.dom_elt, target)) { nearest = pBack.dom_elt; dist = Distance(pBack.dom_elt, target); } if (target.x <= pBack.dom_elt.x) /* Èç¹ûtargetλÓÚpBackµÄ×ó×ӿռ䣬ÄÇô¾ÍÒªÌøµ½ÓÒ×Ó¿Õ¼äÈ¥ËÑË÷ */ { index = 2 * index + 2; pSearch = treeArray[index]; } else /* Èç¹ûtargetλÓÚpBackµÄÓÒ×ӿռ䣬ÄÇô¾ÍÒªÌøµ½×ó×Ó¿Õ¼äÈ¥ËÑË÷ */ { index = 2 * index + 1; pSearch = treeArray[index]; } if (!pSearch.isEmpty) //pSearch¼ÓÈëµ½search_pathÖÐ search_path.push(index); } break; case 1: if (fabs(pBack.dom_elt.y - target.y) < dist) /* Èç¹ûÒÔtargetΪÖÐÐĵÄÔ²£¨Çò»ò³¬Çò£©£¬°ë¾¶ÎªdistµÄÔ²Óë·Ö¸î³¬Æ½ÃæÏཻ£¬ ÄÇô¾ÍÒªÌøµ½ÁíÒ»±ßµÄ×Ó¿Õ¼äÈ¥ËÑË÷ */ { if (Distance(nearest, target) > Distance(pBack.dom_elt, target)) { nearest = pBack.dom_elt; dist = Distance(pBack.dom_elt, target); } if (target.y <= pBack.dom_elt.y) /* Èç¹ûtargetλÓÚpBackµÄ×ó×ӿռ䣬ÄÇô¾ÍÒªÌøµ½ÓÒ×Ó¿Õ¼äÈ¥ËÑË÷ */ { index = 2 * index + 2; pSearch = treeArray[index]; } else /* Èç¹ûtargetλÓÚpBackµÄÓÒ×ӿռ䣬ÄÇô¾ÍÒªÌøµ½×ó×Ó¿Õ¼äÈ¥ËÑË÷ */ { index = 2 * index + 1; pSearch = treeArray[index]; } if (!pSearch.isEmpty) //pSearch¼ÓÈëµ½search_pathÖÐ search_path.push(index); } break; default: if (fabs(pBack.dom_elt.z - target.z) < dist) /* Èç¹ûÒÔtargetΪÖÐÐĵÄÔ²£¨Çò»ò³¬Çò£©£¬°ë¾¶ÎªdistµÄÔ²Óë·Ö¸î³¬Æ½ÃæÏཻ£¬ ÄÇô¾ÍÒªÌøµ½ÁíÒ»±ßµÄ×Ó¿Õ¼äÈ¥ËÑË÷ */ { if (Distance(nearest, target) > Distance(pBack.dom_elt, target)) { nearest = pBack.dom_elt; dist = Distance(pBack.dom_elt, target); } if (target.z <= pBack.dom_elt.z) /* Èç¹ûtargetλÓÚpBackµÄ×ó×ӿռ䣬ÄÇô¾ÍÒªÌøµ½ÓÒ×Ó¿Õ¼äÈ¥ËÑË÷ */ { index = 2 * index + 2; pSearch = treeArray[index]; } else /* Èç¹ûtargetλÓÚpBackµÄÓÒ×ӿռ䣬ÄÇô¾ÍÒªÌøµ½×ó×Ó¿Õ¼äÈ¥ËÑË÷ */ { index = 2 * index + 1; pSearch = treeArray[index]; } if (!pSearch.isEmpty) //pSearch¼ÓÈëµ½search_pathÖÐ search_path.push(index); } break; } } } nearestpoint.x = nearest.x; nearestpoint.y = nearest.y; nearestpoint.z = nearest.z; distance = dist; } int getHeight(TreeNode * T) { if (T == nullptr) { return 0; } int leftheight = getHeight(T->left); int rightheight = getHeight(T->right); return max(leftheight, rightheight) + 1; } void TreeToArray(TreeNode* T, TreeElement* treeArray, int index) { //TreeElement *treeArray = new TreeElement[size]; if (T != nullptr) { treeArray[index].dom_elt = T->dom_elt; treeArray[index].split = T->split; treeArray[index].isEmpty = false; TreeToArray(T->left, treeArray, 2 * index + 1); TreeToArray(T->right, treeArray, 2 * index + 2); } /*else { treeArray[index].dom_elt = *(new coordinate); treeArray[index].split = 0; treeArray[index].isEmpty = true; }*/ }