// prebudovanie stromu // na vstupe je zoznam vsetkych buducich listov podstromu. public KDNode rebuilt(List<KDNode> l1, int dim1, KDNode newParent, Boolean isLeft) { List<KDNode> l = l1; // ak je v zozname iba 1 vrchol, vrati sa ako list if (l.Count == 1) { return l.ElementAt(0); } int newSplit; int dimension; if (newParent == null) { // root ma nastavenu deliacu suradnicu na x. dimension = 0; } else { dimension = 1 - newParent.getDim(); } // vrati split noveho vrchola newSplit = findSplit(l, dimension); //Console.WriteLine(newSplit); List<KDNode> newLeft = new List<KDNode>(); List<KDNode> newRight = new List<KDNode>(); Boolean equal = true; //rozdelenie na 2 podstromy podla split a dim if (dimension == 0) //split cez x-ovu os { foreach (KDNode n in l) { // zoznam listov v lavom a pravom podstrome podla split if (n.getPoint().X < newSplit) { newLeft.Add(n); } if (n.getPoint().X > newSplit) { newRight.Add(n); } // ak by mali rovnaku suradnicu, aby sa nepridavali len do jedneho podstromu if (n.getPoint().X == newSplit) { if (equal){ newLeft.Add(n); equal = false; } else { newRight.Add(n); equal = true; } } } } else { //split cez y-ovu os foreach (KDNode n in l) { // zoznam listov v lavom a pravom podstrome podla split if (n.getPoint().Y < newSplit) { newLeft.Add(n); } if (n.getPoint().Y > newSplit) { newRight.Add(n); } // ak by mali rovnaku suradnicu, aby sa nepridavali len do jedneho podstromu if (n.getPoint().Y == newSplit) { if (equal) { newLeft.Add(n); equal = false; } else { newRight.Add(n); equal = true; } } } } // vytvori sa koren noveho podstromu KDNode subroot = new KDNode(true, newSplit, dimension, null, this.g); if (newParent != null) { if (isLeft) { newParent.setLeft(subroot); } else { newParent.setRight(subroot); } } subroot.setParent(newParent); subroot.setLeft(rebuilt(newLeft, 1 - dimension, subroot, true)); subroot.getLeft().setParent(subroot); subroot.setRight(rebuilt(newRight, 1 - dimension, subroot, false)); subroot.getRight().setParent(subroot); return subroot; }
// najde numNearest najblizsich vrcholov ku target // na konci budu v usporiadanom zozname nearestK public void findNearest(KDNode subTree, KDNode target) { // ak je to list, zistime, ci je blizsie ako doposial najdene, ak ich je dost if (subTree.isLeaf) { subTree.dist = distance(target.getPoint(), subTree.getPoint()); if (nearestK.Count < numNearest) { nearestK.Add(subTree); } else { if (nearestK.Last().dist > subTree.dist) { nearestK.Remove(nearestK.Last()); nearestK.Add(subTree); } } return; } int dim = subTree.getDim(); // ak je target v lavom podstrome, nearer je lavy a further je pravy, inak opacne KDNode nearer; KDNode further; if (dim == 0) { if (subTree.getSplit() >= target.getPoint().X) { nearer = subTree.getLeft(); further = subTree.getRight(); } else { further = subTree.getLeft(); nearer = subTree.getRight(); } } else { if (subTree.getSplit() >= target.getPoint().Y) { nearer = subTree.getLeft(); further = subTree.getRight(); }else { further = subTree.getLeft(); nearer = subTree.getRight(); } } // najprv prehladavame blizsi podstrom // (prvy prehladany blok bude ten, v kt. je target) // teda si ohranicime v priemere celkom slusne najblizsie vrcholy findNearest(nearer, target); // zrata najblizsi bod od target na bunke further // ak je dalej ako doposial najdeny k-ty nejmensi, tak vo further // nemoze byt blizsi bod => nevnara sa Point nearestF = nearestTo(further, target); double dist = distance(nearestF, target.getPoint()); if ((nearestK.Last().dist > dist) || (nearestK.Count < numNearest)) { findNearest(further, target); } }
//vrati podstrom, do ktoreho syna ma ist novy vrchol a bola by v nom narusena rovnovaha public KDNode findPlace(KDNode n, KDNode leaf) { // ak n je list, potom sa rovnovaha nenarusi a iba sa novy vrchol vlozi. // z listu spravime otca dvoch listov v procedure rebuilt if(n.isLeaf) { //Console.Write(n.getPoint()); //Console.WriteLine(" numLeafs " + n.getNumLeafs()); return n; } //Console.Write(n.getSplit()); //Console.WriteLine(" numLeafs right" + n.getRight().getNumLeafs()); //Console.WriteLine(" numLeafs left" + n.getLeft().getNumLeafs()); // ak to nie je list, potom hladame podstrom, ktoremu sa narusi rovnovaha. if (n.getDim() == 0) // split je v x-ovej suradnici { if (n.getSplit() >= leaf.getPoint().X) // ak ma ist do laveho podstromu { // a uz teraz je vlavo viac listov ako vpravo, narusi sa rovnovaha n if (n.getLeft().getNumLeafs() > n.getRight().getNumLeafs()) { return n; } else { // inak sa vrati podstrom z laveho podstromu, v ktorom je narusena rovnovaha return findPlace(n.getLeft(), leaf); } } else { // ak ma ist do praveho podstromu // a uz teraz je vpravo viac listov ako vlavo, narusi sa rovnovaha n if (n.getLeft().getNumLeafs() < n.getRight().getNumLeafs()) { return n; } else { // inak sa vrati podstrom z praveho podstromu, v ktorom je narusena rovnovaha return findPlace(n.getRight(), leaf); } } } else { // split je v y-ovej suradnici if (n.getSplit() >= leaf.getPoint().Y) // ak ma ist do laveho podstromu (= patri hore, nad split) { // a uz teraz je vlavo viac listov ako vpravo, narusi sa rovnovaha n if (n.getLeft().getNumLeafs() > n.getRight().getNumLeafs()) { return n; } else { // inak sa vrati podstrom z laveho podstromu, v ktorom je narusena rovnovaha return findPlace(n.getLeft(), leaf); } } else { // ak ma ist do praveho podstromu (= patri dole, pod split) // a uz teraz je vpravo viac listov ako vlavo, narusi sa rovnovaha n if (n.getLeft().getNumLeafs() < n.getRight().getNumLeafs()) { return n; } else { // inak sa vrati podstrom z praveho podstromu, v ktorom je narusena rovnovaha return findPlace(n.getRight(), leaf); } } } }