You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何高效生成10万个无重复的3D空间Vector3随机点?

高效生成无重复且带聚类效果的3D Vector3点

嘿,这个需求挺实际的!直接像你原代码那样纯随机生成,大概率会出现重复点,而且后期生成重复的概率越来越高,效率极低。要同时满足「10万个无重复点」和「聚类效果」,咱们可以从避免重复生成和定向聚类两个方向入手,下面给你具体的思路和代码示例:

核心思路拆解

1. 高效去重:别生成后再去重,要从源头避免

直接生成后遍历列表去重的时间复杂度是O(n²),10万个点的话会慢到离谱。最优方案是用**哈希集合(HashSet)**记录已经生成的点的唯一标识,每次生成新点先查集合,O(1)的查询速度能把效率拉满。

这里要注意浮点数的精度问题:比如0.1和0.100000001其实是同一个位置(对咱们的需求来说),但直接比较浮点数会被当成不同点。解决办法是把坐标放大转成整数,再生成唯一键(比如字符串),这样就能精准判断重复。

2. 聚类效果:多中心点+偏移生成

要让点呈现聚类效果,不用搞复杂的算法,直接选几个「中心点」,围绕每个中心点生成带随机偏移的点就行:

  • 中心点数量决定聚类的数量(比如8-10个,越多聚类越分散)
  • 偏移范围决定聚类的紧密程度(范围越小,点越集中在中心点周围)
  • 还可以给不同中心点分配不同数量的点,让聚类大小不一样,更自然。

具体代码实现(Java)

下面是修改后的完整代码,包含去重逻辑和聚类生成,你可以直接用:

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Random;

public class Vector3 {
    public float x;
    public float y;
    public float z;

    Vector3(float x, float y, float z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    // 生成唯一键:解决浮点数精度问题,缩放倍数可按需调整
    private String getUniqueKey() {
        int scale = 1000; // 精度到0.001,足够大多数场景使用
        return String.format("%d_%d_%d", 
            Math.round(x * scale), 
            Math.round(y * scale), 
            Math.round(z * scale));
    }

    /**
     * 生成带聚类效果的无重复3D点
     * @param totalPoints 总点数(比如100000)
     * @param minX/X/Y/Z 3D空间的边界
     * @return 无重复的Vector3列表
     */
    public static ArrayList<Vector3> generateClusteredUniqueVectors(
            int totalPoints, 
            float minX, float maxX, 
            float minY, float maxY, 
            float minZ, float maxZ) {
        
        ArrayList<Vector3> resultList = new ArrayList<>();
        HashSet<String> usedKeys = new HashSet<>();
        Random random = new Random();

        // 第一步:生成聚类中心点(数量可调整)
        int clusterCount = 8;
        Vector3[] clusterCenters = new Vector3[clusterCount];
        for (int i = 0; i < clusterCount; i++) {
            float cx = minX + random.nextFloat() * (maxX - minX);
            float cy = minY + random.nextFloat() * (maxY - minY);
            float cz = minZ + random.nextFloat() * (maxZ - minZ);
            clusterCenters[i] = new Vector3(cx, cy, cz);
        }

        // 第二步:给每个聚类分配点数(随机分配,保证总和是totalPoints)
        int[] pointsPerCluster = new int[clusterCount];
        int remainingPoints = totalPoints;
        for (int i = 0; i < clusterCount - 1; i++) {
            // 每个聚类至少1个点,最多分剩下的一半
            pointsPerCluster[i] = 1 + random.nextInt(remainingPoints - (clusterCount - i - 1));
            remainingPoints -= pointsPerCluster[i];
        }
        pointsPerCluster[clusterCount - 1] = remainingPoints;

        // 第三步:围绕每个中心点生成点
        for (int i = 0; i < clusterCount; i++) {
            Vector3 center = clusterCenters[i];
            int needGenerate = pointsPerCluster[i];
            // 聚类偏移范围:比如边界的1/10,越小聚类越集中
            float offsetX = (maxX - minX) * 0.1f;
            float offsetY = (maxY - minY) * 0.1f;
            float offsetZ = (maxZ - minZ) * 0.1f;

            while (needGenerate > 0) {
                // 生成中心点附近的随机点
                float x = center.x + (random.nextFloat() * 2 - 1) * offsetX;
                float y = center.y + (random.nextFloat() * 2 - 1) * offsetY;
                float z = center.z + (random.nextFloat() * 2 - 1) * offsetZ;

                // 确保点在边界内
                x = Math.max(minX, Math.min(maxX, x));
                y = Math.max(minY, Math.min(maxY, y));
                z = Math.max(minZ, Math.min(maxZ, z));

                Vector3 newVec = new Vector3(x, y, z);
                String key = newVec.getUniqueKey();

                if (!usedKeys.contains(key)) {
                    usedKeys.add(key);
                    resultList.add(newVec);
                    needGenerate--;
                }
            }
        }

        return resultList;
    }

    // 测试用例
    public static void main(String[] args) {
        ArrayList<Vector3> vectors = generateClusteredUniqueVectors(
            100000, 0, 100, 0, 100, 0, 100);
        System.out.println("成功生成点数:" + vectors.size());
    }
}

更高效的进阶方案:基于网格的生成

如果你的3D空间足够大(比如能划分出至少10万个不重叠的小网格),可以用网格离散化的方式,完全避免重复点的生成,效率更高:

// 基于网格的高效生成:每个点来自不同网格单元,绝对无重复
public static ArrayList<Vector3> generateGridBasedClusteredVectors(
        int totalPoints, 
        float minX, float maxX, 
        float minY, float maxY, 
        float minZ, float maxZ,
        float gridSize) {
    
    ArrayList<Vector3> resultList = new ArrayList<>();
    HashSet<String> usedGrids = new HashSet<>();
    Random random = new Random();

    // 计算网格数量
    int gridX = (int) Math.ceil((maxX - minX) / gridSize);
    int gridY = (int) Math.ceil((maxY - minY) / gridSize);
    int gridZ = (int) Math.ceil((maxZ - minZ) / gridSize);

    // 生成聚类中心点对应的网格
    int clusterCount = 8;
    ArrayList<int[]> clusterGrids = new ArrayList<>();
    for (int i = 0; i < clusterCount; i++) {
        int gx = random.nextInt(gridX);
        int gy = random.nextInt(gridY);
        int gz = random.nextInt(gridZ);
        clusterGrids.add(new int[]{gx, gy, gz});
    }

    // 分配每个聚类的点数
    int[] pointsPerCluster = new int[clusterCount];
    int remainingPoints = totalPoints;
    for (int i = 0; i < clusterCount - 1; i++) {
        pointsPerCluster[i] = 1 + random.nextInt(remainingPoints - (clusterCount - i - 1));
        remainingPoints -= pointsPerCluster[i];
    }
    pointsPerCluster[clusterCount - 1] = remainingPoints;

    // 生成每个聚类的点:围绕中心点网格的附近网格
    for (int i = 0; i < clusterCount; i++) {
        int[] centerGrid = clusterGrids.get(i);
        int needGenerate = pointsPerCluster[i];
        int gridOffset = 2; // 聚类覆盖的网格范围,越大越分散

        while (needGenerate > 0) {
            // 在中心点网格的偏移范围内选网格
            int gx = centerGrid[0] + random.nextInt(gridOffset * 2 + 1) - gridOffset;
            int gy = centerGrid[1] + random.nextInt(gridOffset * 2 + 1) - gridOffset;
            int gz = centerGrid[2] + random.nextInt(gridOffset * 2 + 1) - gridOffset;

            // 跳过超出边界的网格
            if (gx < 0 || gx >= gridX || gy < 0 || gy >= gridY || gz < 0 || gz >= gridZ) {
                continue;
            }

            String gridKey = gx + "_" + gy + "_" + gz;
            if (!usedGrids.contains(gridKey)) {
                usedGrids.add(gridKey);
                // 在网格内随机生成点
                float x = minX + gx * gridSize + random.nextFloat() * gridSize;
                float y = minY + gy * gridSize + random.nextFloat() * gridSize;
                float z = minZ + gz * gridSize + random.nextFloat() * gridSize;
                resultList.add(new Vector3(x, y, z));
                needGenerate--;
            }
        }
    }

    return resultList;
}

这种方式的好处是完全不会有重复点,因为每个点都来自独立的网格单元,生成速度极快,适合对效率要求极高的场景。

最后调整建议

  • 聚类数量:修改clusterCount的值,越多聚类越分散
  • 聚类紧密程度:调整offsetX/Y/Z的系数(比如改成0.05,聚类会更集中)
  • 精度控制:修改getUniqueKey里的scale值,比如要更高精度就用10000

内容的提问来源于stack exchange,提问作者Hyperegg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 11:52:53