如何将二叉树就地转换为二叉搜索树,即我们不能使用任何额外的空间

时间:2010-04-05 05:47:00

标签: algorithm data-structures tree binary-tree binary-search-tree

如何在适当的位置将二叉树转换为二叉搜索树,即我们不能使用任何额外的空间。

11 个答案:

答案 0 :(得分:14)

将二进制树转换为双向链表 - 可以在O(n)中进行 然后使用合并排序对其进行排序,nlogn
将列表转换回树 - O(n)

简单的nlogn解决方案。

答案 1 :(得分:11)

你没有给予太多的帮助,但是如果要求是我认为的那样,那么你已经创建了一个二进制树并且坐在内存中,但是没有排序(你想要它的排序方式,无论如何)。

我假设树节点看起来像

struct tree_node {
    struct tree_node * left;
    struct tree_node * right;
    data_t data;
};

我也假设你可以阅读C

虽然我们可以坐下来想知道为什么这个树是在没有按照排序顺序创建的情况下创建的,这对我们没有好处,所以我会忽略它并只处理它的排序。

不使用额外空间的要求是奇怪的。暂时会有额外的空间,如果只是在堆栈上。我将假设这意味着调用malloc或类似的东西,并且结果树不得不使用比原始未排序树更多的内存。

第一个也是最简单的解决方案是对未排序的树执行前序遍历,从树中删除每个节点并对新树进行排序插入。这是O(n + n log(n)),即O(n log(n))。

如果这不是他们想要的东西,你将不得不使用旋转和东西.....这太可怕了!

我认为你可以通过做一个奇怪版本的堆排序来做到这一点,但我遇到了问题。 我想到的另一件事情,即速度非常慢,会在树上做一个奇怪的冒泡排序。

为此,每个节点都会被比较,并且可能会与每个节点的直接子节点(因此也与其父节点)重复交换,直到您遍历树并且找不到任何节点。 需要交换。执行一个振动器排序(从左到右和从右到左的冒泡排序)版本的效果最好,并且在初始传递之后,您不需要遍历那些看起来没有关于它的父级的子树

我确信这个algorthm在我面前被其他人想到了,并且有一个我不知道的名字,或者它在某种程度上是我根本没有看到的缺陷。

提出第二个建议的运行时计算是非常复杂的。起初我认为它只是O(n ^ 2),就像泡沫和振动器类型一样,但我不能满足自己,子树遍历避免可能不会赢得足够的比O(n ^更好) 2)。基本上泡沫和振动筛排序也可以得到这种优化,但只有在总排序性提前发生的末端才能达到极限。使用这个树版本,您可以获得机会,以避免在集合中间的块。好吧,就像我说的那样,它可能存在致命的缺陷。

答案 2 :(得分:2)

执行PostOrder Traversal并从中创建二进制搜索树。

struct Node * newroot = '\0';

struct Node* PostOrder(Struct Node* root)
{
      if(root != '\0')
      {
          PostOrder(root->left);
          PostOrder(root->right);
          insertBST(root, &newroot);
      }
}

insertBST(struct Node* node, struct Node** root)
{
   struct Node * temp, *temp1;
   if( root == '\0')
   {
      *root == node;
       node->left ==  '\0';
       node->right == '\0';
   }
   else
   {
       temp = *root;
       while( temp != '\0')
       {
           temp1= temp;
           if( temp->data > node->data)
               temp = temp->left;
           else
               temp = temp->right;
       }
       if(temp1->data > node->data)
       {
           temp1->left = node;
       }
       else
       {
           temp1->right = node;
       }
       node->left = node->right = '\0';
    }
}

答案 3 :(得分:1)

执行以下算法以达到解决方案。

1)在不使用任何空格的情况下找到顺序继承者。

Node InOrderSuccessor(Node node)
{ 
    if (node.right() != null) 
    { 
        node = node.right() 
        while (node.left() != null)  
            node = node.left() 
        return node 
    }
    else
    { 
        parent = node.getParent(); 
        while (parent != null && parent.right() == node)
       { 
            node = parent 
            parent = node.getParent() 
        } 
        return parent 
    } 
} 

2)按顺序进行遍历而不使用空格。

a)找到inorder遍历的第一个节点。它应该留下树的大部分孩子,如果它有,或者如果它有,则留下第一个正确的孩子,或者留给孩子本身。 b)使用上述算法找出第一个节点的inoder后继。 c)对所有返回的后继者重复步骤2.

使用上面的2算法并在二叉树上进行顺序遍历而不使用额外的空间。 在进行遍历时形成二叉搜索树。但复杂性是O(N2)最坏的情况。

答案 4 :(得分:0)

二进制树通常二进制搜索树,在这种情况下不需要转换。

也许你需要弄清楚你要转换的结构。您的源树是否不平衡?是否按您要搜索的密钥排序?你是怎么到达源树的?

答案 5 :(得分:0)

好吧,如果这是一个面试问题,我首先要脱口而出(实际上没有想到)是这样的:递归地迭代整个二进制并找到最小的元素。把它从二叉树中取出来。现在,重复迭代整个树并找到最小元素的过程,并将其添加为找到的最后一个元素的父元素(前一个元素成为新节点的左子元素)。根据需要重复多次,直到原始树为空。最后,你留下了最糟糕的排序二进制树 - 一个链表。您的指针指向根节点,这是最大的元素。

这是一个可怕的算法全能 - O(n ^ 2)运行时间与最差的二叉树输出,但它是一个不错的起点,然后提出更好的东西,并具有你能够写的优势它的代码在白板上大约20行。

答案 6 :(得分:0)

#include <stdio.h>
#include <stdlib.h>

typedef int data_t;

struct tree_node {
    struct tree_node * left;
    struct tree_node * right;
    data_t data;
};

        /* a bonsai-tree for testing */
struct tree_node nodes[10] =
{{ nodes+1, nodes+2, 1}
,{ nodes+3, nodes+4, 2}
,{ nodes+5, nodes+6, 3}
,{ nodes+7, nodes+8, 4}
,{ nodes+9, NULL, 5}
,{ NULL, NULL, 6}
,{ NULL, NULL, 7}
,{ NULL, NULL, 8}
,{ NULL, NULL, 9}
        };

struct tree_node * harvest(struct tree_node **hnd)
{
struct tree_node *ret;

while (ret = *hnd) {
        if (!ret->left && !ret->right) {
                *hnd = NULL;
                return ret;
                }
        if (!ret->left ) {
                *hnd = ret->right;
                ret->right = NULL;;
                return ret;
                }
        if (!ret->right) {
                *hnd = ret->left;
                ret->left = NULL;;
                return ret;
                }
        hnd = (rand() &1) ? &ret->left : &ret->right;
        }

return NULL;
}

void insert(struct tree_node **hnd, struct tree_node *this)
{
struct tree_node *ret;

while ((ret= *hnd)) {
        hnd = (this->data  < ret->data ) ? &ret->left : &ret->right;
        }
*hnd = this;
}

void show(struct tree_node *ptr, int indent)
{
if (!ptr) { printf("Null\n"); return; }

printf("Node(%d):\n", ptr->data);
printf("%*c=", indent, 'L');  show (ptr->left, indent+2);
printf("%*c=", indent, 'R');  show (ptr->right, indent+2);
}

int main(void)
{
struct tree_node *root, *this, *new=NULL;

for (root = &nodes[0]; this = harvest (&root);  ) {
        insert (&new, this);
        }

show (new, 0);
return 0;
}

答案 7 :(得分:0)

struct Node
{
    int value;
    Node* left;
    Node* right;
};

void swap(int& l, int& r)
{
    int t = l;
    l = r;
    r = t;
}

void ConvertToBST(Node* n, Node** max)
{
    if (!n) return;

    // leaf node
    if (!n->left && !n->right)
    {
        *max = n;
        return;
    }

    Node *lmax = NULL, *rmax = NULL;
    ConvertToBST(n->left, &lmax);
    ConvertToBST(n->right, &rmax);

    bool swapped = false;
    if (lmax && n->value < lmax->value)
    {
        swap(n->value, lmax->value);
        swapped = true;
    }

    if (rmax && n->value > rmax->value)
    {
        swap(n->value, n->right->value);
        swapped = true;
    }

    *max = n;
    if (rmax && rmax->value > n->value) *max = rmax;

    // If either the left subtree or the right subtree has changed, convert the tree to BST again
    if (swapped) ConvertToBST(n, max);
}

答案 8 :(得分:0)

***I am giving this solution in Java***

import javafx.util.Pair;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;

public class MinimumSwapRequiredBTintoBST {
    //Node of binary tree
    public static class Node{
        int data;
        Node left;
        Node right;
        public Node(int data){
            this.data = data;
            this.left = null;
            this.right = null;
        }
    }
    public static void main(String []arg){
        root = new Node(1);
        root.left = new Node(2);
        root.right = new Node(3);
        root.left.left = new Node(4);
        root.left.right = new Node(5);
        root.right.left = new Node(6);
        root.right.right = new Node(7);
        System.out.print("Tree traverasl i.e inorder traversal :");
        inorder(root);
        System.out.println(" ");
        MinimumSwapRequiredBTintoBST bst = new MinimumSwapRequiredBTintoBST();
        bst.convertBTBST(root);
    }

    private static void inorder(Node root) {
        if(root == null) return;
        inorder(root.left);
        System.out.print(root.data + "  ");
        inorder(root.right);

    }

   static Node root;
    int[] treeArray;
    int index = 0;

// convert binary tree to binary search tree
    public void convertBTBST(Node node){
        int treeSize = elementsOfTree(node);
        treeArray = new int[treeSize];
        convertBtToArray(node);
        // Sort Array ,Count number of swap

        int minSwap = minimumswap(treeArray);
        System.out.println("Minmum swap required to form BT to BST :" +minSwap);
    }

    private static int minimumswap(int[] arr) {
        int n =arr.length;
        // Create two arrays and use as pairs where first
        // is element and secount array as position of first element
        ArrayList<Pair<Integer, Integer>> arrpos =
            new ArrayList<Pair<Integer, Integer>>();
        // Assign the value
        for(int i =0;i<n;i++)
        {
            arrpos.add(new Pair<Integer, Integer>(arr[i],i));
        }
// Sort the array by array element values to get right
//position of every element as the elements of secound array

        arrpos.sort(new Comparator<Pair<Integer, Integer>>() {
            @Override
            public int compare(Pair<Integer, Integer> o1, Pair<Integer, Integer> o2) {
                return o1.getKey()-o2.getKey();
            }
        });
// To keep track of visited elements .Initially all elements as not visited so put them as false
        int ans = 0;
        boolean []visited = new boolean[n];
        Arrays.fill(visited, false);
        // Traverse array elements
        for(int i =0;i<n;i++){
            // Already swapped and corrected or already present at correct pos
            if(visited[i] || arrpos.get(i).getValue() == i)
                continue;
            // Find out the number of nodes in this cycle and add in ans
            int cycle_size = 0;
            int j =i;
            while(!visited[j]){
                visited[j] = true;
                j = arrpos.get(j).getValue();
                cycle_size++;
            }
            if(cycle_size>0){
                ans += cycle_size-1;
            }
        }
        return ans;
    }

    private void convertBtToArray(Node node) {
        // Check whether tree is empty or not.
        if (root == null) {
            System.out.println("Tree is empty:");
            return;
        }
    else{
        if(node.left != null) {
         convertBtToArray(node.left);}
            treeArray[index] = node.data;
            index++;
            if(node.right != null){
                convertBtToArray(node.right);
            }

        }
    }
    private int elementsOfTree(Node node) {
        int height = 0;
        if(node == null) return 0;
        else{
            height = elementsOfTree(node.left )+ elementsOfTree(node.right)+1;
        }
        return height;
    }


}

答案 9 :(得分:-1)

按顺序遍历二叉树并存储结果。 按结果排序结果 通过将排序列表的中间元素作为根来形成二进制搜索树(这可以使用二进制搜索来完成)。所以我们得到了平衡的二叉搜索树。

答案 10 :(得分:-1)

堆排序树.. nlogn复杂..