如何用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
相关产品推荐
相关产品推荐

