AVL树数据过滤及树形文件浏览器多维度排序实现问询
2. 如何给树形结构指定多维度排序准则?
你的核心问题是当前AVL树的插入逻辑是硬编码的(默认用Archivo的operator<),无法动态切换排序维度。解决思路是让AVL树支持自定义比较器,把排序逻辑从树内部解耦,这样就能按需切换名称、大小、日期等排序规则了。
具体实现步骤:
第一步:给Archivo类补充属性访问方法
确保能方便获取文件的名称、大小、日期等属性,让比较器可以访问这些值:
class Archivo { private: string fileName; size_t fileSize; time_t creationDate; // 其他成员变量、构造函数(比如从路径初始化属性) public: // 添加只读访问方法 const string& GetName() const { return fileName; } size_t GetSize() const { return fileSize; } time_t GetCreationDate() const { return creationDate; } };
第二步:修改AVL树,支持自定义比较器
把AVL树改成模板类,让它接受比较器作为模板参数(或构造时传入比较函数),插入节点时用指定规则确定位置:
// 带比较器的AVL树模板 template <typename T, typename Comparator = less<T>> class AVLTree { private: struct Node { T* data; int height; Node* left; Node* right; Node(T* val) : data(val), height(1), left(nullptr), right(nullptr) {} }; Node* root; Comparator compare; // 存储自定义比较器 // 辅助方法:获取节点高度 int GetHeight(Node* node) { return node ? node->height : 0; } // 递归插入:用compare比较节点 Node* InsertRecursive(Node* current, T* value) { if (!current) return new Node(value); // 用自定义比较器决定插入左/右子树 if (compare(*value, *current->data)) { current->left = InsertRecursive(current->left, value); } else { current->right = InsertRecursive(current->right, value); } // 更新高度并平衡树(AVL树核心逻辑,省略旋转细节) current->height = 1 + max(GetHeight(current->left), GetHeight(current->right)); int balance = GetHeight(current->left) - GetHeight(current->right); // 处理四种失衡情况(左左、左右、右右、右左) // ... return current; } // 递归中序遍历:调用回调处理节点 void InOrderRecursive(Node* current, function<void(T*)> visitor) const { if (!current) return; InOrderRecursive(current->left, visitor); visitor(current->data); InOrderRecursive(current->right, visitor); } public: // 构造函数:接受自定义比较器,默认用less<T> AVLTree(Comparator comp = Comparator()) : root(nullptr), compare(comp) {} void Insert(T* value) { root = InsertRecursive(root, value); } void InOrderTraversal(function<void(T*)> visitor) const { InOrderRecursive(root, visitor); } // 析构函数:释放节点内存,避免泄漏 ~AVLTree() { function<void(Node*)> deleteNodes = [&](Node* node) { if (!node) return; deleteNodes(node->left); deleteNodes(node->right); delete node->data; delete node; }; deleteNodes(root); } };
第三步:定义不同维度的比较器
为每个排序维度写一个比较器结构体,实现operator()定义比较规则:
// 按文件名升序排序 struct CompareByNameAsc { bool operator()(const Archivo& a, const Archivo& b) const { return a.GetName() < b.GetName(); } }; // 按文件大小降序排序 struct CompareBySizeDesc { bool operator()(const Archivo& a, const Archivo& b) const { return a.GetSize() > b.GetSize(); } }; // 按创建日期升序排序 struct CompareByDateAsc { bool operator()(const Archivo& a, const Archivo& b) const { return a.GetCreationDate() < b.GetCreationDate(); } };
第四步:按需使用不同的排序树
现在可以根据需求创建不同的AVL树实例,插入文件后就能得到对应排序的结果:
// 示例:按文件名排序的树 AVLTree<Archivo, CompareByNameAsc> nameSortedTree; // 遍历目录插入文件的通用方法 void BuscarArchivos(AVLTree<Archivo>& targetTree, const string& path) { for (const auto& entry : fs::directory_iterator(path)) { Archivo* arc = new Archivo(entry.path().string()); targetTree.Insert(arc); } } // 调用示例 string path; cout << "Ingrese la ruta: "; cin >> path; BuscarArchivos(nameSortedTree, path); // 输出按名称排序的文件信息 cout << "按名称排序的文件列表:" << endl; nameSortedTree.InOrderTraversal([](Archivo* file) { cout << "名称:" << file->GetName() << " | 大小:" << file->GetSize() << "字节" << " | 创建日期:" << ctime(&file->GetCreationDate()); }); // 如果需要按大小排序,只需创建另一个树实例 AVLTree<Archivo, CompareBySizeDesc> sizeSortedTree; BuscarArchivos(sizeSortedTree, path); // 输出按大小排序的结果...
额外提示:
- 若不想修改现有AVL树结构,也可以临时重载
Archivo的operator<来切换排序逻辑,但这种方式灵活性差,推荐用模板比较器方案。 - 记得处理内存泄漏:你用
new创建了Archivo对象,一定要在树的析构函数中释放内存(上面的模板已包含析构逻辑)。
内容的提问来源于stack exchange,提问作者Lino Mac Kay
相关产品推荐
相关产品推荐

