当前位置: 首页 > 知识库问答 >
问题:

在树本身内重新排序二叉查找树

左丘楷
2023-03-14

如果给我一个无序的二叉树,那么在不创建新树的情况下对它进行排序的最佳方法是什么?当我说排序时,我的意思是左子树中的所有节点都小于根节点,而右子树中的所有节点都大于根节点。

我很欣赏将无序二叉树变成二叉树的最最佳方法是提取所有节点,然后将它们插入到新树中,但是是否有另一种方法涉及切换原始树中节点的位置,可以通过算法完成?

共有1个答案

仇浩旷
2023-03-14

创建新树的方法当然是要走的路,但作为一种练习,可以就地对二叉树进行排序。

例如,您可以实现冒泡排序,这样所有节点都保持不变,但它们的值会在此过程中交换。

为此,您需要实现按顺序遍历。然后继续重复完整的无序遍历,其中比较两个连续访问的节点的值,如果它们的顺序不正确,则交换它们的值。当顺序遍历不会导致至少一次交换时,将对树进行排序,并且该过程可以停止。

下面是一个JavaScript实现:

它首先生成一个树,其中包含 10 个节点,其随机无符号整数小于 100。树的形状也是随机的(基于每次插入时提供的随机“路径”)

然后如上所述对树进行排序。由于JavaScript支持生成器和迭代器,所以我使用了这种语法,但也可以用回调系统来实现。

它以非常基本的方式显示树(旋转90°,即根在左侧),因为它是在排序操作之前和之后。

class Node {
    constructor(value) {
        this.value = value;
        this.left = this.right = null;
    }
}

class Tree {
    constructor() {
        this.root = null;
    }
    // Method to add a value as a new leaf node, using the 
    //   binary bits in the given path to determine 
    //   the leaf's location:
    addAtPath(value, path) {
        function recur(node, path) {
            if (!node) return new Node(value);
            if (path % 2) {
                node.right = recur(node.right, path >> 1);
            } else {
                node.left = recur(node.left, path >> 1);
            }
            return node;
        }
        this.root = recur(this.root, path);
    }
    *inorder() {
        function* recur(node) {
            if (!node) return;
            yield* recur(node.left);
            yield node;
            yield* recur(node.right);
        }
        yield* recur(this.root);
    }
    toString() {
        function recur(node, indent) {
            if (!node) return "";
            return recur(node.right, indent + "   ")
                 + indent + node.value + "\n"
                 + recur(node.left, indent + "   ");
        }
        return recur(this.root, "");
    }
    bubbleSort() {
        let dirty = true;
        while (dirty) {
            dirty = false;
            let iterator = this.inorder();
            // Get first node from inorder traversal
            let prevNode = iterator.next().value;
            for (let currNode of iterator) { // Get all other nodes
                if (prevNode.value > currNode.value) { 
                    // Swap
                    const temp = prevNode.value;
                    prevNode.value = currNode.value;
                    currNode.value = temp;
                    dirty = true;
                }
                prevNode = currNode;
            }
        }
    }
}

// Helper
const randInt = max => Math.floor(Math.random() * max);

// Demo:
const tree = new Tree();
for (let i = 0; i < 10; i++) {
    tree.addAtPath(randInt(100), randInt(0x80000000));
}
console.log("Tree before sorting (root is at left, leaves at the right):");
console.log(tree.toString());
tree.bubbleSort();
console.log("Tree after sorting:");
console.log(tree.toString());
 类似资料:
  • 主要内容:什么是二叉排序树?,使用二叉排序树查找关键字,二叉排序树中插入关键字,二叉排序树中删除关键字,总结前几节介绍的都是有关静态 查找表的相关知识,从本节开始介绍另外一种查找表—— 动态查找表。 动态查找表中做查找操作时,若查找成功可以对其进行删除;如果查找失败,即表中无该关键字,可以将该关键字插入到表中。 动态查找表的表示方式有多种,本节介绍一种使用树结构表示动态查找表的实现方法—— 二叉排序树(又称为 “二叉查找树”)。 什么是二叉排序树? 二叉排序树要么是空 二叉树,要么具有如下特点:

  • 我正在努力实现二叉搜索树。完成实现所需的功能之一是重新平衡功能。 根据规范,该功能的工作方式如下: rebalance() 方法应创建一个平衡树,从而将偏度降低为零。平衡树是指在整个树中,左子树和右子树的大小相差不超过1(即,每个子树也是平衡的)。 为了平衡树,rebalance() 方法应反复将根值移动到较小的子树,并将最小/最大值从较大的子树移动到根,直到树平衡。然后,它应该以递归方式平衡两个

  • 我们已经看到了两种不同的方法来获取集合中的键值对。回想一下,这些集合实现了 map 抽象数据类型。我们讨论的 map ADT 的两个实现是在列表和哈希表上的二分搜索。在本节中,我们将研究二叉查找树作为从键映射到值的另一种方法。 在这种情况下,我们对树中项的确切位置不感兴趣,但我们有兴趣使用二叉树结构来提供高效的搜索。

  • 二叉树查找 思路说明 二叉树查找是一个面对动态数据比较常用的查找算法。本文根据下面地址文章翻译,并根据本人的理解进行适当修改。 原文地址:http://www.laurentluce.com/posts/binary-search-tree-library-in-python/comment-page-1/ 二叉树查找的定义 定义内容可以参阅Wikipedia:http://en.wikipedi

  • 我试图使用队列的链表实现实现二叉搜索树的级别顺序遍历。 我已经检查了二叉查找树的实现,它是好的。队列的链表实现也是正确的。在这里,我试图访问节点并将其子节点排队。然后使用弹出函数实际访问节点。 这最终是通过递归调用完成的。当我运行以下代码时,我以不同的顺序获得输出。

  • HLOJ 9576,习题7-2 二叉排序树 输入一个整数关键字序列,生成一棵用链式存储结构存储的二叉排序树,对该二叉排序树能进行查找和插入结点的操作,并对该二叉排序树中结点的关键字按递增和递减顺序输出。 要求依次完成以下工作: (1) 以这n个整数生成(建立)一棵用链式存储结构存储的二叉排序树; (2) 按递增顺序输出该二叉排序树中的整数(关键字); (3) 输入一个整数key1,对该二叉排序树进