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

如何用std::sort基于结构体z值排序并调整粒子索引顺序

问题:基于粒子Z位置排序并调整索引而非移动粒子本身

我实在不明白为什么我的问题被判定为重复,其他示例都是对结构体中的变量进行排序,而我要实现的是基于结构体中一个变量对另一个变量排序,找不到相关示例。

具体需求

我开发了一个用于学习的基础粒子系统,粒子结构体定义如下:

struct Particle {
float px;  // x坐标
float py;  // y坐标
float pz;  // z坐标
float scale;
float rotation;
float red;
float green;
float blue;
float alpha;
int index; // 粒子ID
};

新建粒子会存入std::vector<Particle> particles;,最终通过这个数组绘制粒子。

现在需要添加深度排序步骤,实现从远到近绘制粒子。已知可以用std::sort提升性能,但我的需求是:基于粒子的pz(z位置)排序,仅调整粒子的index来得到正确绘制顺序,而非移动整个粒子结构体。

我了解到常规的结构体排序写法是这样的:

std::sort(particles.begin(), particles.end(), [](const auto& lhs, const auto& rhs)
    {
        return lhs.pz > rhs.pz;
    });

但这会直接重排particles数组里的粒子对象,不符合我的需求。我查阅了很多示例都找不到相关实现,求修改方案。

附言:当前使用的低效排序算法

以下是我目前在用的排序代码,速度极慢(双重循环),想换成std::sort优化。这是结构体改造前的代码,变量名略有不同,仅作演示(counter为粒子总数):

for (int i = 0; i < counter - 1; ++i) {
    for (int j = 0; j < counter - 1; ++j) {
        int p = particles[j].index;
        int q = particles[j + 1].index;

        if ( particles[p].pz > particles[q].pz) {
            unsigned int tmp = particles[j].index;
            particles[j].index = particles[j + 1].index;
            particles[j + 1].index = tmp;
        }
    }
}

解决方案及性能对比

@PaulMcKenzie帮助我解决了问题,他编写的示例代码经我调整后验证可行,性能提升显著:原双重循环算法耗时16秒,使用std::sort的方案仅需3.8秒。

实现代码

#include <algorithm>
#include <vector>
#include <numeric>
#include <iostream>
#include <random>

struct Particle {
float px;  // x坐标
float py;  // y坐标
float pz;  // z坐标
float scale;
float rotation;
float red;
float green;
float blue;
float alpha;
};

int main()
{
    // 随机数生成器,用于生成测试用的z坐标
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_real_distribution<float> zValues(1.0f, 1000.0f);
   
    // 创建10个粒子并赋予随机z值
    std::vector<Particle> vParticles(10);
    for (auto& v : vParticles )
       v.pz = zValues(gen);

    std::vector<int> index(10);
    std::cout << "原始z值顺序:\n";
    for (auto& v : vParticles)        
      std::cout << v.pz << "\n";

    // 初始化索引数组为0~9,对应粒子数组的原始索引
    std::iota(index.begin(), index.end(), 0);

    // 基于粒子的z值对索引数组排序(从小到大,即从近到远;如需从远到近改成>即可)
    std::sort(index.begin(), index.end(), [&](int n1, int n2) 
        { return vParticles[n1].pz < vParticles[n2].pz;});

    std::cout << "\n按z值排序后的顺序:\n";
    for (auto& i : index)        
      std::cout << vParticles[i].pz << " " << " 对应的原粒子索引是 " << i << "\n";

    std::cout << "\n最终的排序索引数组:\n";
    for (auto& i : index)        
        std::cout << i << "\n";

    std::cout << "\n验证:原粒子数组未被修改:\n";
    for (auto& v : vParticles)        
      std::cout << v.pz << "\n";
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 05:07:32