Encontre o ponto mais próximo com o melhor desempenho

Para encontrar os pontos mais próximos com melhor desempenho, uma abordagem comum é usar estruturas de dados espaciais para acelerar o processo de busca. Aqui estão duas estruturas de dados comuns e suas aplicações:

  1. Árvore KD (KD-Tree): A árvore KD é uma estrutura de dados de árvore binária usada para segmentar e organizar pontos no espaço k-dimensional. Ele pode suportar com eficiência a pesquisa do vizinho mais próximo. Ao construir uma árvore KD, os pontos são divididos recursivamente em subárvores esquerda e direita, de modo que cada nó represente uma área hiperretangular. Ao pesquisar, você pode pesquisar os galhos da árvore passo a passo de acordo com a localização do ponto alvo, reduzindo assim o número e o escopo das pesquisas. A complexidade temporal das operações de construção e busca da árvore KD é O(log n), onde n é o número de pontos.
  2. Quadtree: Quadtree é uma estrutura de dados em árvore que divide o espaço bidimensional. Ele divide o espaço em quatro quadrantes e divide cada quadrante recursivamente até que a condição de terminação seja alcançada. Armazene referência de ponto ou informações de densidade em cada nó. Através do quadtree, o espaço pode ser dividido em diferentes níveis para localizar e procurar rapidamente o ponto mais próximo. A complexidade de tempo das operações de construção e busca da quadtree é O(log n), onde n é o número de pontos.

Estas estruturas de dados espaciais podem ser selecionadas e implementadas de acordo com as necessidades reais. A complexidade de tempo de construção da estrutura de dados pode ser alta, mas os pontos mais próximos podem ser encontrados rapidamente durante a pesquisa subsequente do vizinho mais próximo, melhorando assim o desempenho. Observe que, para conjuntos de dados muito grandes, você também pode considerar o uso de estruturas de dados ou algoritmos mais avançados para otimizar ainda mais a eficiência da pesquisa.

Alternativamente, se o número de pontos não for muito grande, você também pode usar um método de percurso simples, calculando e atualizando os pontos mais próximos durante o processo de percurso. A complexidade de tempo deste método é O(n), onde n é o número de pontos. Embora o desempenho deste método seja fraco, pode ser suficiente para conjuntos de dados de pequena escala.

Como implementar a árvore KD

Implementar uma árvore KD pode ser uma tarefa complexa que envolve construção de árvore, inserção e operações de pesquisa. A seguir está um exemplo simples de implementação de uma árvore KD, mostrando as ideias básicas de construção, inserção e pesquisa do vizinho mais próximo:

using UnityEngine;
using System.Collections.Generic;

public class KdTree
{
    
    
    private class KdTreeNode
    {
    
    
        public Vector3 position;
        public KdTreeNode left;
        public KdTreeNode right;

        public KdTreeNode(Vector3 position)
        {
    
    
            this.position = position;
            left = null;
            right = null;
        }
    }

    private KdTreeNode root;

    public void Insert(Vector3 position)
    {
    
    
        root = InsertRecursive(root, position, 0);
    }

    private KdTreeNode InsertRecursive(KdTreeNode node, Vector3 position, int depth)
    {
    
    
        if (node == null)
        {
    
    
            return new KdTreeNode(position);
        }

        int axis = depth % 3; // 3维空间,根据深度选择切分轴

        if (position[axis] < node.position[axis])
        {
    
    
            node.left = InsertRecursive(node.left, position, depth + 1);
        }
        else
        {
    
    
            node.right = InsertRecursive(node.right, position, depth + 1);
        }

        return node;
    }

    public KdTreeNode FindNearest(Vector3 targetPosition)
    {
    
    
        if (root == null)
        {
    
    
            return null;
        }

        KdTreeNode nearestNode = null;
        float nearestDistance = float.MaxValue;

        FindNearestRecursive(root, targetPosition, 0, ref nearestNode, ref nearestDistance);

        return nearestNode;
    }

    private void FindNearestRecursive(KdTreeNode node, Vector3 targetPosition, int depth, ref KdTreeNode nearestNode, ref float nearestDistance)
    {
    
    
        if (node == null)
        {
    
    
            return;
        }

        float distance = Vector3.Distance(node.position, targetPosition);

        if (distance < nearestDistance)
        {
    
    
            nearestNode = node;
            nearestDistance = distance;
        }

        int axis = depth % 3; // 3维空间,根据深度选择切分轴

        if (targetPosition[axis] < node.position[axis])
        {
    
    
            FindNearestRecursive(node.left, targetPosition, depth + 1, ref nearestNode, ref nearestDistance);

            // 检查是否需要在另一个子树搜索
            if (Mathf.Abs(targetPosition[axis] - node.position[axis]) < nearestDistance)
            {
    
    
                FindNearestRecursive(node.right, targetPosition, depth + 1, ref nearestNode, ref nearestDistance);
            }
        }
        else
        {
    
    
            FindNearestRecursive(node.right, targetPosition, depth + 1, ref nearestNode, ref nearestDistance);

            // 检查是否需要在另一个子树搜索
            if (Mathf.Abs(targetPosition[axis] - node.position[axis]) < nearestDistance)
            {
    
    
                FindNearestRecursive(node.left, targetPosition, depth + 1, ref nearestNode, ref nearestDistance);
            }
        }
    }
}

No código acima, definimos uma classe interna KdTreeNode para representar os nós da árvore KD. Cada nó contém uma posição, subnó esquerdo à esquerda e subnó direito à direita.

O processo de construção de uma árvore KD é implementado recursivamente, utilizando a função InsertRecursive para inserir novos nós na árvore. Em cada nó, selecionamos o eixo de divisão com base na profundidade atual e inserimos o novo nó na subárvore esquerda ou direita com base no valor do eixo de divisão.

O processo de busca do vizinho mais próximo também é implementado recursivamente, usando a função FindNearestRecursive para encontrar o nó mais próximo. Em cada nó, calculamos a distância entre o local de destino e a localização atual do nó e atualizamos o nó mais próximo e a distância mais próxima. Em seguida, com base na profundidade atual e no valor do eixo de divisão, escolha pesquisar mais na subárvore esquerda ou na subárvore direita e determine se você precisa pesquisar em outra subárvore com base na distância do eixo de divisão atual.

Observe que o código acima é uma implementação simplificada da árvore KD, mostrando apenas as ideias básicas de construção, inserção e pesquisa do vizinho mais próximo. Para aplicações mais complexas, pode ser necessário considerar mais detalhes e otimizações. Além disso, a implementação da árvore KD aqui é para o espaço tridimensional.Se precisar processar dados em outras dimensões, será necessário fazer os ajustes correspondentes.

Se você quiser usar uma implementação de árvore KD mais completa e de alto desempenho, é recomendável encontrar uma biblioteca de árvore KD existente ou consultar tutoriais e documentação mais detalhados para implementação.

Acho que você gosta

Origin blog.csdn.net/hhh314159/article/details/131210413
Recomendado
Clasificación