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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:42:30