private VPTreeNode CreateNode(int lowerIndex, int upperIndex) { if (upperIndex == lowerIndex) { return(null); } VPTreeNode node = new VPTreeNode(lowerIndex); if (upperIndex - lowerIndex > 1) { Swap(data, lowerIndex, this.randomizer.Next(lowerIndex + 1, upperIndex)); int medianIndex = (upperIndex + lowerIndex) / 2; int comparsion(T i1, T i2) => Comparer <int> .Default.Compare(this.analyzer.CalculateDistance(data[lowerIndex], i1), this.analyzer.CalculateDistance(data[lowerIndex], i2)); NthElement(data, lowerIndex + 1, medianIndex, upperIndex - 1, comparsion); node.radius = this.analyzer.CalculateDistance(this.data[lowerIndex], this.data[medianIndex]); node.left = CreateNode(lowerIndex + 1, medianIndex); node.right = CreateNode(medianIndex, upperIndex); } return(node); }
private void Search(VPTreeNode node, T target, List <HeapItem> closestHits) { if (node == null) { return; } int dist = this.analyzer.SearchComparator(this.data[node.dataIndex], target); if (dist <= this.tau) { closestHits.Add(new HeapItem(node.dataIndex, dist)); } if (node.left == null && node.right == null) { return; } if (dist < node.radius) { if (dist - this.tau <= node.radius) { this.Search(node.left, target, closestHits); } if (dist + this.tau >= node.radius) { this.Search(node.right, target, closestHits); } } else { if (dist + this.tau >= node.radius) { this.Search(node.right, target, closestHits); } if (dist - this.tau <= node.radius) { this.Search(node.left, target, closestHits); } } }
/// <summary> /// Create VP-tree using INodeAnalyzer.CalculateDistance for node distance calculating /// </summary> public void Create(T[] data, INodeAnalyzer <T> analyzer) { this.data = data; this.analyzer = analyzer; this.root = this.CreateNode(0, data.Length); }