/// <summary> /// 从cur节点开始向子树中寻找x的最近邻 /// </summary> /// <param name="cur">开始查找的根节点</param> private void Query(KD_TreeNode cur) { if (cur == null) return; //求出目标x到当前节点的距离 double dist = Dist(cur.data.value, curQuery.value); if (check.Contains(cur.data.index)==false && dist<curNearestDist) { //当前节点未被提取过且dist小于当前最近距离 curNearestDist = dist; curNearestNode = cur.data.index; } //计算x到分裂平面的距离 double radius = Math.Pow(curQuery.value[cur.split] - cur.data.value[cur.split], 2); //对子区间进行查询 if (curQuery.value[cur.split]<cur.data.value[cur.split]) { Query(cur.left); if (radius <= curNearestDist) Query(cur.right); } else { Query(cur.right); if (radius <= curNearestDist) Query(cur.left); } }
public KD_Tree(KD_DataType[] s) { dataset = s; dimension = s[0].value.Count(); root = BuildTree(0, s.Count() - 1); }
/// <summary> /// 对区间head到tail之间的点建树 /// </summary> /// <param name="head"></param> /// <param name="tail"></param> /// <returns>当前节点</returns> private KD_TreeNode BuildTree(int head, int tail) { if (head > tail) return null; //计算每一维上的方差,并找到方差最大的维度 double maxVariance = 0; int bestDimension = 0; for (int s = 0; s < dimension; s++) { double variance = 0; double sum = 0; for (int i = head; i <= tail; i++) sum += dataset[i].value[s]; double avr = sum / (double)(tail - head + 1); for(int i=head;i<=tail; i++) variance += Math.Pow(dataset[i].value[s] - avr, 2); variance /= (double)(tail - head + 1); if (variance>maxVariance) { maxVariance = variance; bestDimension = s; } } //新节点 KD_TreeNode newNode = new KD_TreeNode(); newNode.split = bestDimension; //将区间内的点按best dimension排序 Dictionary<KD_DataType, double> unsort = new Dictionary<KD_DataType, double>(); for (int i = head; i <= tail; i++) { unsort.Add(dataset[i], dataset[i].value[bestDimension]); } var sorted = from pair in unsort orderby pair.Value ascending select pair; var arrSorted = sorted.ToArray(); for(int i = head;i<=tail;i++) { dataset[i] = arrSorted[i - head].Key; } //建立左右子树 //sort(head, tail, bestDimension); int mid = head + (tail - head) / 2; newNode.data = dataset[mid]; newNode.left = BuildTree(head, mid - 1); newNode.right = BuildTree(mid + 1, tail); return newNode; }