perf(scene): 使用哈希表优化节点添加和删除操作

优化 Scene 和 Node 类的子节点管理,通过引入 unordered_map 存储节点索引,将删除操作的时间复杂度从 O(n) 降低到 O(1)。同时防止重复添加相同节点。
This commit is contained in:
ChestnutYueyue 2026-03-16 19:16:00 +08:00
parent 95d9e7c5c4
commit 3df1703839
4 changed files with 34 additions and 12 deletions

View File

@ -6,6 +6,7 @@
#include <types/math/mat4.h> #include <types/math/mat4.h>
#include <types/ptr/intrusive_ptr.h> #include <types/ptr/intrusive_ptr.h>
#include <string> #include <string>
#include <unordered_map>
#include <vector> #include <vector>
namespace extra2d { namespace extra2d {
@ -315,6 +316,7 @@ private:
bool visible_ = true; bool visible_ = true;
Node* parent_ = nullptr; Node* parent_ = nullptr;
std::vector<Ptr<Node>> children_; std::vector<Ptr<Node>> children_;
std::unordered_map<Node*, size_t> childIndices_;
std::vector<Ptr<Component>> components_; std::vector<Ptr<Component>> components_;
TransformComponent* transform_ = nullptr; TransformComponent* transform_ = nullptr;
}; };

View File

@ -3,6 +3,7 @@
#include <scene/node.h> #include <scene/node.h>
#include <types/ptr/intrusive_ptr.h> #include <types/ptr/intrusive_ptr.h>
#include <string> #include <string>
#include <unordered_map>
#include <vector> #include <vector>
namespace extra2d { namespace extra2d {
@ -115,6 +116,7 @@ public:
protected: protected:
std::vector<Ptr<Node>> rootNodes_; std::vector<Ptr<Node>> rootNodes_;
std::unordered_map<Node*, size_t> rootNodeIndices_;
CameraComponent* mainCamera_ = nullptr; CameraComponent* mainCamera_ = nullptr;
bool entered_ = false; bool entered_ = false;
}; };

View File

@ -29,6 +29,7 @@ Node::~Node() {
void Node::addChild(Ptr<Node> child) { void Node::addChild(Ptr<Node> child) {
if (!child || child.get() == this) return; if (!child || child.get() == this) return;
if (childIndices_.find(child.get()) != childIndices_.end()) return;
// 从原父节点移除 // 从原父节点移除
if (child->parent_) { if (child->parent_) {
@ -36,18 +37,25 @@ void Node::addChild(Ptr<Node> child) {
} }
child->parent_ = this; child->parent_ = this;
childIndices_[child.get()] = children_.size();
children_.push_back(child); children_.push_back(child);
} }
void Node::removeChild(Node* child) { void Node::removeChild(Node* child) {
if (!child) return; if (!child) return;
for (auto it = children_.begin(); it != children_.end(); ++it) { auto indexIt = childIndices_.find(child);
if (it->get() == child) { if (indexIt == childIndices_.end()) {
child->parent_ = nullptr; return;
children_.erase(it); }
return;
} const size_t removeIndex = indexIt->second;
child->parent_ = nullptr;
children_.erase(children_.begin() + removeIndex);
childIndices_.erase(indexIt);
for (size_t i = removeIndex; i < children_.size(); ++i) {
childIndices_[children_[i].get()] = i;
} }
} }
@ -62,6 +70,7 @@ void Node::removeAllChildren() {
child->parent_ = nullptr; child->parent_ = nullptr;
} }
children_.clear(); children_.clear();
childIndices_.clear();
} }
// ======================================== // ========================================

View File

@ -16,21 +16,29 @@ Scene::~Scene() {
void Scene::addChild(Ptr<Node> node) { void Scene::addChild(Ptr<Node> node) {
if (!node) return; if (!node) return;
if (rootNodeIndices_.find(node.get()) != rootNodeIndices_.end()) return;
node->removeFromParent(); node->removeFromParent();
node->onEnter(); node->onEnter();
rootNodeIndices_[node.get()] = rootNodes_.size();
rootNodes_.push_back(node); rootNodes_.push_back(node);
} }
void Scene::removeChild(Node* node) { void Scene::removeChild(Node* node) {
if (!node) return; if (!node) return;
for (auto it = rootNodes_.begin(); it != rootNodes_.end(); ++it) { auto indexIt = rootNodeIndices_.find(node);
if (it->get() == node) { if (indexIt == rootNodeIndices_.end()) {
node->onExit(); return;
rootNodes_.erase(it); }
return;
} const size_t removeIndex = indexIt->second;
node->onExit();
rootNodes_.erase(rootNodes_.begin() + removeIndex);
rootNodeIndices_.erase(indexIt);
for (size_t i = removeIndex; i < rootNodes_.size(); ++i) {
rootNodeIndices_[rootNodes_[i].get()] = i;
} }
} }
@ -39,6 +47,7 @@ void Scene::removeAllChildren() {
node->onExit(); node->onExit();
} }
rootNodes_.clear(); rootNodes_.clear();
rootNodeIndices_.clear();
} }
Node* Scene::findNode(const std::string& name) { Node* Scene::findNode(const std::string& name) {