【问题标题】:Sorting the elements in Binary trees对二叉树中的元素进行排序
【发布时间】:2013-03-19 18:13:43
【问题描述】:

这是我最近在一次采访中被问到的一个问题。给出一棵二叉树,条件是每个左孩子比根小 1,右孩子比根大 1。这是一个示例树

按 O(1) 和 O(n) 时间复杂度排序。

以下是我建议的方法:

  1. 使用计数来维护每个元素的计数,然后在完成整个遍历后返回 O(n) 时间和 O(n) 空间复杂度。
  2. 使用游程编码。当元素以数字为键,以计数为值重复时形成一个链。只有当 no 重复时才需要空间用于计数,因此除了数组之外不需要额外的空间,但时间复杂度将是 O(n log n),因为我们必须遍历数组以查看它是否存在。
  3. 最后我建议使用广度优先遍历。我们需要 O(log n) 的队列空间和 O(n) 的时间复杂度(假设插入是 O(1) 链表)。

你的方法是什么?

【问题讨论】:

  • “O(1) 和 O(n) 时间复杂度”是什么意思?你的意思是 O(1) 空间?我可以想象有一个 O(n) 算法,通过以类似于 AVL 树的方式平衡树,然后进行中序遍历。
  • 排序到底是什么意思?该方法需要返回一个排序列表?打印?我们可以修改树吗?
  • O(1) 空间是真正的需求吗?在 O(1) 空间中进行任何遍历似乎都很难(如果我们不能修改树)。也许是 O(高度)?顺便说一句,bfs 占用 Omega(n) 空间。不是 O(log n)。
  • o(1) 空间作为严格要求。把你的观点放在 BFS 上,它是 Omega(n)。有人提到你不应该使用任何额外的空间并在 o(n) 时间内完成。在O(高度)的想法之间。排序意味着返回一个排序的列表。
  • 如何在 o(1) 空间中构建一个长度为 n 的列表?你的意思是你需要我们毁掉这棵树来腾出空间?

标签: algorithm sorting binary-tree


【解决方案1】:

将给定树的某个叶节点修复为 NewHead 。

编写一个函数 Pop() 从给定的树中删除一些节点..!

编写 pop 节点,只有在它存在时才将其删除!等于 NewHead 。

所以从树中弹出值,将其插入到以新头为头节点的新二叉搜索树中。

所以你将从树中删除一个元素并将其添加到新的搜索树中。

直到树头点 NewHead。

所以你所有的元素现在都在二叉搜索树中,指向新的 head ,这将是

显然是按顺序排列的。

这种方式保证你在 O(NlogN) 中进行排序。

【讨论】:

  • 这似乎是一个更好的解决方案。进行深度优先遍历但直接从队列移动到节点是一种解决方案。将它与列表(o(1)插入)一起使用将给出空间复杂度为o(h)的o(n)解决方案。
【解决方案2】:

分析

鉴于您对二叉树的定义,我们有以下内容,

每个节点都有一个 Parent、L-child 和 R-child .. 其中:

L < N

R > N

P > N

我们也可以这样做:

L < N AND R > N => L < N < R => L < R

L < N AND P > N => L < N < P => L < P

R > N AND P > N => N < MIN(P,R)

N < MIN(P,R) AND L < N => L < N < MIN(P,R)

现在让我们尝试扩展它,N.L = Left-child of N

N.L < N
N.R > N
N.P > N

N.L.L < N.L < MIN(N, N.L.R)
N.L.R > N.L > N.L.L

N.R.L < N.R < MIN(N, N.R.R)
N.R.R > N.R > N.R.L

IF N IS N.P LEFT-CHILD: N < N.P < MIN(N.P.P, N.P.R)

IF N IS N.P RIGHT-CHILD: N > N.P.R

建议的解决方案

这个问题看起来很复杂,但我的解决方案是在以左-右-父遍历顺序插入值后使用合并排序,这将有助于合并排序获得介于其平均情况和最佳情况之间的时间复杂度,但具有使用我上面所做的比较的小技巧。

首先,我们使用 Left-Right-Parent 遍历将树节点收集到一个列表中,考虑到以下事实:N.L &lt; N &lt; MIN(N.R, N.P) 并假设 O(N.R) &lt;= O(N.P) 赋予父级更高的权重,当我们向左移动时值线性减小每次.. &gt; N.R.R &gt; N.R &gt; N &gt; N.L &gt; N.L.L &gt; ..

按遍历顺序收集树节点后,列表有一些排序的块,这将有助于我们接下来使用的合并排序。

此解决方案适用于:Time = O(n log n + n)Space = O(n)

这是用Java编写的算法(未测试)

private class Node Comparable<Node>
{
    public Node R;
    public Node L;
    public int value;

    public Node (Node L, int val, Node R)
    {
        this.L = L;
        this.value = val;
        this.R = R;
    }

    @Override
    public int compareTo(Node other)
    {
        return ((other != null) ? (this.value-other.value) : 0);
    }
}

class Main
{
    private static Node head;

    private static void recursive_collect (Node n, ArrayList<Node> list)
    {
        if (n == null) return;
        if (n.left != null) recursive_collect (n.L, list);
        if (n.right != null) recursive_collect (n.R, list);
        list.add(n.value);
    }

    public static ArrayList<Node> collect ()
    {
        ArrayList<Node> list = new ArrayList<Node>();
        recursive_collect (head, list);
        return list;
    }

    // sorting the tree: O(n log n + n)
    public static ArrayList<Node> sortTree ()
    {
        // Collecting nodes: O(n)
        ArrayList<Node> list = collect();

        // Merge Sort: O(n log n)
        Collections.sort(list);

        return list;
    }

    // The example in the picture you provided
    public static void createTestTree ()
    {
        Node left1 = new Node (new Node(null,-2,null), -1, new Node(null,0,null));

        Node left2 = new Node (new Node(null,-1,null), 0, new Node(null,1,null));

        Node right = new Node (left2, 1, new Node(null,2,null));

        head = new Node (left1, 0, right);
    }

    // test
    public static void main(String [] args)
    {
        createTestTree ();

        ArrayList<Node> list = sortTree ();

        for (Node n : list)
        {
            System.out.println(n.value);
        }
    }
}

【讨论】:

    【解决方案3】:

    我猜,您正在寻找 DFS(深度优先搜索)。 在深度优先搜索中,想法是在回溯之前从邻居到邻居尽可能深入。决定可能有多深的是您必须遵循边,并且您不会两次访问任何顶点。

    boost 已经提供了它:见here

    【讨论】:

      【解决方案4】:

      使用快速排序。

      节点在多个数组中按最低级别排序,这些排序元素的数组最后合并。

      例如

      函数 quick_sort(node n)
      1. 进入left模式,如果不为null,调用quick_sort就可以了。
      2. 到右边的元素,如果不为null,调用quick_sort就可以了。
      3.合并左节点排序&右节点排序&当前节点的结果。
      4. 返回合并后的数组。

      【讨论】:

        【解决方案5】:

        我没有得到这个问题。二叉树不是已经排序了吗?如果您想按顺序打印出项目(或按顺序访问它们),此代码将起作用

        /**
        * Show the contents of the BST in order
        */
        public void show () {
        show(root);
        System.out.println();
        }
        private static void show(TreeNode node) {
        if (node == null) return;
        show(node.lchild);
        System.out.print(node.datum + " ");
        show(node.rchild);
        } 
        

        我相信这将是 o(n) 复杂度。要返回列表而不是打印,只需创建一个并通过将子项添加到列表中来替换每个 show 语句

        【讨论】:

        • 不,数字不是按顺序排列的。!您需要对它们进行排序并更改数字的位置..!!
        • @Jessica 您在“二叉搜索树”和“二叉树”之间感到困惑。问题明确指出“二叉树排序”和您提到的代码是 BST 的中序遍历,这里不是这种情况。
        猜你喜欢
        • 2015-11-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-19
        • 2010-11-19
        相关资源
        最近更新 更多