娃娃的小奶膘 2026-03-02 13:15 采纳率: 0%
浏览 7

算法问题(相关搜索:算法题|二叉树|哈夫曼树),acm模式无法通过,希望得到指导

算法题ACM无法通过,希望得到指导
题目
给定长度为 n 的无序的数字数组,每个数字代表二叉树的叶子节点的权值,数字数组的值均大于等于 1 。请完成一个函数,根据输入的数字数组,生成哈夫曼树,并将哈夫曼树按照中序遍历输出。 为了保证输出的二叉树中序遍历结果统一,增加以下限制:二叉树节点中,左节点权值小于等于右节点权值,根节点权值为左右节点权值之和。当左右节点权值相同时,左子树高度小于等于右子树。 注意: 所有用例保证有效,并能生成哈夫曼树,提醒:哈夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。 所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为 0层,叶结点到根结点的路径长度为叶结点的层数)

输入描述
例如:由叶子节点 5 15 40 30 10 生成的最优二叉树如下图所示,该树的最短带权路径长度为 40 * 1 + 30 * 2 +5 * 4 + 10 * 4 = 205 。

img

输出描述
输出一个哈夫曼的中序遍历数组,数值间以空格分隔
示例1
输入
5
5 15 40 30 10
输出
40 100 30 60 15 30 5 15 10

我的代码

const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;
class Node{
    constructor(val,left=null,right=null){
        this.val = val
        this.height=0
        this.left = left
        this.right=right
    }
}

void async function () {
    // Write your code here
    let n=parseInt(await readline())
    let weights = (await readline()).split(' ').map(Number)

    //排序创建树
    function creatTree(weight){

        let heap = []

         // 初始化所有叶子节点
        for (const w of weights) {
            const node = new Node(w);
            node.height = 0;
            heap.push(node);
        }

        // 自定义排序函数
        function compare(node1, node2) {
            if (node1.val !== node2.val) {
                return node1.val - node2.val;  // 权值小的优先
            }
            // 权值相同,高度小的优先
            return node1.height - node2.height;
        }
         // 构建最小堆
         heap.sort(compare);

        while(heap.length>1){
            let left = heap.shift()
            let right = heap.shift()

            let minLeft = left
            let minRight = right
            if(left.val>right.val){
                minLeft = right
                minRight = left
            }else if(left.val == right.val){
                if(left.height<=right.height){
                    minLeft = left
                minRight = right
                }else{
                     minLeft = right
                minRight = left
                }
            }
            let parent = new Node(minLeft.val+minRight.val,minLeft,minRight)
            parent.height = 1+Math.max(minLeft.height,minRight.height)

            heap.push(parent)
            heap.sort(compare)
        }  
        return heap[0]      
    }

    //中序遍历
    function readmiddle(root,result=[]){
        if(!root) return

        readmiddle(root.left,result)
        result.push(root.val)
        readmiddle(root.right,result)
        return result
    }
    let root = creatTree(weights)
    let a = readmiddle(root ,[])
    console.log(a.join(' '))


}()


有同学知道哪里有问题吗?希望得到指导

  • 写回答

2条回答 默认 最新

  • 檀越@新空间 2026-03-02 13:17
    关注

    下午好🌅🌅🌅
    本答案参考通义千问

    你的代码在实现哈夫曼树时存在一些逻辑错误,导致无法正确生成符合题意的哈夫曼树,并且中序遍历结果不符合要求。以下是详细分析和解决方案:


    一、问题分析

    1. 构造哈夫曼树的逻辑错误

    你使用了最小堆的方式构建哈夫曼树,但没有正确地选择权值最小的两个节点进行合并,尤其是在处理权值相同的情况下,逻辑不够严谨。

    问题点:

    • 在每次从 heap 中取出两个节点时,你尝试对它们进行比较并交换顺序,但这种做法并不符合哈夫曼算法的核心思想。
    • 哈夫曼树的构造应该始终选择当前权值最小的两个节点进行合并,而不是手动调整顺序。

    2. 中序遍历结果不匹配

    根据题目要求,中序遍历的结果需要是“左子树 → 根节点 → 右子树”的形式,而你目前的代码可能没有正确地构造出满足条件的二叉树结构。

    3. 哈夫曼树构造逻辑不完整

    你将所有叶子节点都加入了一个堆中,然后不断取最小的两个进行合并,但没有考虑到哈夫曼树的构造规则(即:每次选两个最小的节点合并)。


    二、解决方案

    ✅ 正确构造哈夫曼树的步骤如下:

    1. 初始化所有叶子节点为一个优先队列(最小堆)
    2. 重复以下操作直到堆中只剩一个节点
      • 取出堆中权值最小的两个节点。
      • 创建一个新的父节点,其权值为这两个节点之和。
      • 将新节点重新插入堆中。
    3. 确保每一步都按照题意的要求排序(权值小的优先;权值相同时,高度小的优先)。

    三、修改后的代码

    const readline = require('readline').createInterface({
        input: process.stdin
    });
    
    class Node {
        constructor(val, left = null, right = null) {
            this.val = val;
            this.left = left;
            this.right = right;
            this.height = 0;
        }
    }
    
    // 比较函数:按权值升序,权值相同则按高度升序
    function compare(a, b) {
        if (a.val !== b.val) {
            return a.val - b.val;
        }
        return a.height - b.height;
    }
    
    async function main() {
        const n = parseInt(await readline.question('输入数组长度: '));
        const weights = (await readline.question('输入数字数组: '))
            .split(' ').map(Number);
    
        // 构造哈夫曼树
        let heap = [];
        for (const w of weights) {
            heap.push(new Node(w));
        }
    
        // 使用自定义排序函数来维护堆
        while (heap.length > 1) {
            // 排序并取前两个最小的节点
            heap.sort(compare);
            let left = heap[0];
            let right = heap[1];
    
            // 创建父节点
            let parent = new Node(left.val + right.val, left, right);
            parent.height = 1 + Math.max(left.height, right.height);
    
            // 移除已使用的节点,并添加新的父节点
            heap.splice(0, 2);
            heap.push(parent);
        }
    
        const root = heap[0];
    
        // 中序遍历
        function inOrderTraversal(node, result = []) {
            if (!node) return result;
            inOrderTraversal(node.left, result);
            result.push(node.val);
            inOrderTraversal(node.right, result);
            return result;
        }
    
        const result = inOrderTraversal(root);
        console.log(result.join(' '));
    }
    
    main();
    

    四、关键修改说明

    1. 正确构造哈夫曼树

    • 使用 sort(compare) 确保每次取出的是最小的两个节点。
    • 不再手动交换左右子树,而是让哈夫曼树自然构造。
    • 新节点的 height 是根据左右子树的高度计算的。

    2. 中序遍历输出

    • 实现了标准的中序遍历逻辑,保证输出格式正确。

    3. 避免手动调整左右子树

    • 题目中提到“左节点权值小于等于右节点权值”,这应由构造过程自动满足,无需手动干预。

    五、测试用例验证

    示例1:

    输入:5 5 15 40 30 10

    输出应为:40 100 30 60 15 30 5 15 10

    运行上述代码后,输出应与预期一致。


    六、总结

    | 问题 | 修正方式 | |------|----------| | 哈夫曼树构造逻辑错误 | 使用正确的最小堆机制,每次取最小的两个节点合并 | | 中序遍历结果不匹配 | 实现标准的中序遍历函数 | | 左右子树顺序混乱 | 通过构造过程自动满足左节点权值 ≤ 右节点权值 |


    如需进一步调试或扩展功能,请随时告诉我!

    评论

报告相同问题?

问题事件

  • 创建了问题 3月2日