Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 合并2个二叉搜索树_Algorithm_Binary Tree - Fatal编程技术网

Algorithm 合并2个二叉搜索树

Algorithm 合并2个二叉搜索树,algorithm,binary-tree,Algorithm,Binary Tree,如何合并2个二叉搜索树,使结果树包含这两个树的所有元素,并维护BST属性 我看到了中提供的解决方案 但是,该解决方案需要转换为一个双链接列表。我想知道是否有一种更优雅的方法可以做到这一点,而不需要转换。我提出了以下伪代码。它适用于所有情况吗?我还有第三个病例的问题 node* merge(node* head1, node* head2) { if (!head1) return head2; if (!head2)

如何合并2个二叉搜索树,使结果树包含这两个树的所有元素,并维护BST属性

我看到了中提供的解决方案

但是,该解决方案需要转换为一个双链接列表。我想知道是否有一种更优雅的方法可以做到这一点,而不需要转换。我提出了以下伪代码。它适用于所有情况吗?我还有第三个病例的问题

node* merge(node* head1, node* head2) {
        if (!head1)
            return head2;
        if (!head2)
            return head1;

        // Case 1.
        if (head1->info > head2->info) {
            node* temp = head2->right;
            head2->right = NULL;
            head1->left = merge(head1->left, head2);
            head1 = merge(head1, temp);
            return head1;
        } else if (head1->info < head2->info)  { // Case 2
            // Similar to case 1.
        } else { // Case 3
            // ...
        }
}
节点*合并(节点*头1,节点*头2){
如果(!头1)
返回头2;
如果(!头2)
返回头1;
//案例1。
如果(头1->信息>头2->信息){
节点*temp=head2->右侧;
head2->right=NULL;
head1->left=合并(head1->left,head2);
head1=合并(head1,temp);
返回头1;
}否则如果(head1->infoinfo){//Case 2
//与案例1类似。
}else{//案例3
// ...
}
}

BST是一个有序或排序的二叉树。我的算法非常简单:

  • 穿过两棵树
  • 比较这些值
  • 将两者中较小的一个插入新的BST
用于遍历的python代码如下所示:

def traverse_binary_tree(node, callback):
    if node is None:
        return
    traverse_binary_tree(node.leftChild, callback)
    callback(node.value)
    traverse_binary_tree(node.rightChild, callback)

穿越BST并构建新的合并BST的成本将保持O(n)

我们可以将树合并到位的最佳方法如下:

For each node n in first BST {
    Go down the 2nd tree and find the appropriate place to insert n
    Insert n there
}

for循环中的每个迭代都是O(logn),因为我们处理的是树,而for循环将被迭代n次,所以总共有O(nlogn).

假设我们有两棵树A和B,我们将树A的根插入树B,并使用旋转移动插入的根以成为树B的新根。接下来,我们递归地合并树A和B的左、右子树。该算法考虑了两棵树的结构,但插入仍然取决于目标树的平衡程度。您可以使用这个想法来合并
O(n+m)
时间和
O(1)
空间中的两棵树


以下实施是由于:

//将树转换为已排序的单链表并将其追加
//返回现有列表的标题,并返回新标题。
//左指针用作下一个单独形成表单的指针
//链表从而基本上形成了退化的
//单个左向分支。榜首
//到元素最大的节点。
静态TreeNode ToSortedList(TreeNode树,TreeNode头)
{
if(tree==null)
//没有要转换和附加的内容
回流头;
//使用顺序遍历进行转换
//转换第一个左子树并将其附加到
//现有清单
head=ToSortedList(tree.Left,head);
//将根添加到列表并将其用作新的头
树。左=头;
//转换右子树并将其附加到列表中
//已包含左子树和根
返回到排序列表(tree.Right,tree);
}
//将两个排序的单链表合并为一个和
//计算合并列表的大小。合并列表使用
//右指针形成单链表,从而形成
//单右向分支的退化树。
//头部指向具有最小元素的节点。
静态TreeNode合并分类列表(TreeNode左、TreeNode右、IComparer比较器、out int size)
{
TreeNode头=空;
尺寸=0;
//有关链表,请参见合并排序的合并阶段
//唯一的区别在于这种实现
//在合并期间还原列表
while(左!=null | |右!=null)
{
下一步;
if(left==null)
下一步=拆卸和推进(参考右侧);
else if(right==null)
下一步=拆卸和前进(参考左侧);
其他的
next=comparer.Compare(left.Value,right.Value)>0
?拆卸和推进(参考左侧)
:DetachAndAdvance(参考右侧);
下一个。右=头;
头=下一个;
大小++;
}
回流头;
}
静态TreeNode DetacheAndAdvance(参考TreeNode节点)
{
var tmp=节点;
node=node.Left;
tmp.Left=null;
返回tmp;
}
//将单链表转换为二叉搜索树
//将列表头推进到下一个未使用的列表节点,然后
//返回创建的树根
静态树节点ToBinarySearchTree(参考树节点头部,内部尺寸)
{
如果(大小==0)
//大小为零的列表转换为空
返回null;
树根;
如果(大小==1)
{
//单位大小的列表转换为具有
//左指针和右指针设置为空
根=头;
//将头前进到列表中的下一个节点
头=头。对;
//左指针是唯一正确的指针
//无效
root.Right=null;
返回根;
}
var leftSize=size/2;
var rightSize=size-leftSize-1;
//用列表节点的一半创建左子树
var leftRoot=ToBinarySearchTree(ref head,leftSize);
//列表头现在指向子树的根
//正在创建
根=头;
//预选名单的头和名单的其余部分将
//用于创建正确的子树
头=头。对;
//将左子树链接到根
root.Left=leftRoot;
//创建右子树并将其链接到根
root.Right=ToBinarySearchTree(参考头部,右尺寸);
返回根;
}
公共静态TreeNode合并(TreeNode左、TreeNode右、IComparer比较器)
{
Contract.Requires(comparer!=null);
如果(左==null | |右==null)
返回左→右;
//使用原始树节点将两棵树转换为已排序列表
var leftList=ToSortedList(左,空);
var rightList=ToSortedList(右,空);
整数大小;
//合并已排序的列表并计算合并的列表大小
var list=合并分类列表(左列表、右列表、比较器、输出大小);
//
// Converts tree to sorted singly linked list and appends it
// to the head of the existing list and returns new head.
// Left pointers are used as next pointer to form singly
// linked list thus basically forming degenerate tree of
// single left oriented branch. Head of the list points
// to the node with greatest element.
static TreeNode<T> ToSortedList<T>(TreeNode<T> tree, TreeNode<T> head)
{
    if (tree == null)
        // Nothing to convert and append
        return head;
    // Do conversion using in order traversal
    // Convert first left sub-tree and append it to
    // existing list
    head = ToSortedList(tree.Left, head);
    // Append root to the list and use it as new head
    tree.Left = head;
    // Convert right sub-tree and append it to list
    // already containing left sub-tree and root
    return ToSortedList(tree.Right, tree);
}

// Merges two sorted singly linked lists into one and
// calculates the size of merged list. Merged list uses
// right pointers to form singly linked list thus forming
// degenerate tree of single right oriented branch.
// Head points to the node with smallest element.
static TreeNode<T> MergeAsSortedLists<T>(TreeNode<T> left, TreeNode<T> right, IComparer<T> comparer, out int size)
{
    TreeNode<T> head = null;
    size = 0;
    // See merge phase of merge sort for linked lists
    // with the only difference in that this implementations
    // reverts the list during merge
    while (left != null || right != null)
    {
        TreeNode<T> next;
        if (left == null)
            next = DetachAndAdvance(ref right);
        else if (right == null)
            next = DetachAndAdvance(ref left);
        else
            next = comparer.Compare(left.Value, right.Value) > 0
                        ? DetachAndAdvance(ref left)
                        : DetachAndAdvance(ref right);
        next.Right = head;
        head = next;
        size++;
    }
    return head;
}



static TreeNode<T> DetachAndAdvance<T>(ref TreeNode<T> node)
{
    var tmp = node;
    node = node.Left;
    tmp.Left = null;
    return tmp;
}

// Converts singly linked list into binary search tree
// advancing list head to next unused list node and
// returning created tree root
static TreeNode<T> ToBinarySearchTree<T>(ref TreeNode<T> head, int size)
{
    if (size == 0)
        // Zero sized list converts to null
        return null;

    TreeNode<T> root;
    if (size == 1)
    {
        // Unit sized list converts to a node with
        // left and right pointers set to null
        root = head;
        // Advance head to next node in list
        head = head.Right;
        // Left pointers were so only right needs to
        // be nullified
        root.Right = null;
        return root;
    }

    var leftSize = size / 2;
    var rightSize = size - leftSize - 1;
    // Create left substree out of half of list nodes
    var leftRoot = ToBinarySearchTree(ref head, leftSize);
    // List head now points to the root of the subtree
    // being created
    root = head;
    // Advance list head and the rest of the list will
    // be used to create right subtree
    head = head.Right;
    // Link left subtree to the root
    root.Left = leftRoot;
    // Create right subtree and link it to the root
    root.Right = ToBinarySearchTree(ref head, rightSize);
    return root;
}

public static TreeNode<T> Merge<T>(TreeNode<T> left, TreeNode<T> right, IComparer<T> comparer)
{
    Contract.Requires(comparer != null);

    if (left == null || right == null)
        return left ?? right;
    // Convert both trees to sorted lists using original tree nodes
    var leftList = ToSortedList(left, null);
    var rightList = ToSortedList(right, null);
    int size;
    // Merge sorted lists and calculate merged list size
    var list = MergeAsSortedLists(leftList, rightList, comparer, out size);
    // Convert sorted list into optimal binary search tree
    return ToBinarySearchTree(ref list, size);
}
Spine 1: time = O(n1),    space = O(1) 
Spine 2: time = O(n2),    space = O(1) 
Merge:   time = O(n1+n2), space = O(1) 
Balance: time = O(n1+n2), space = O(1) 
Total:   time = O(n1+n2), space = O(1)
Node* merge(Node* n1, Node* n2) {
    Node *prev, *head1, *head2;   
    prev = head1 = 0; spine(n1, prev, head1); 
    prev = head2 = 0; spine(n2, prev, head2);
    return balance(mergeSpines(head1, head2));
}
void spine(Node *p, Node *& prev, Node *& head) {   
    if (!p) return;   
    spine(p->left, prev, head);   
    if (prev) prev->right = p;   
    else head = p;  
    prev = p; 
    p->left = 0;  
    spine(p->right, prev, head); 
} 
void advance(Node*& last, Node*& n) {
    last->right = n; 
    last = n;
    n = n->right; 
}

Node* mergeSpines(Node* n1, Node* n2) {
    Node head;
    Node* last = &head;
    while (n1 || n2) {
        if (!n1) advance(last, n2);
        else if (!n2) advance(last, n1);
        else if (n1->info < n2->info) advance(last, n1);
        else if (n1->info > n2->info) advance(last, n2);
        else {
            advance(last, n1);
            printf("Duplicate key skipped %d \n", n2->info);
            n2 = n2->right;
        }
    }
    return head.right; 
}
Node* balance(Node *& list, int start, int end) {
    if (start > end) return NULL;  
    int mid = start + (end - start) / 2;    
    Node *leftChild = balance(list, start, mid-1);   
    Node *parent = list;
    parent->left = leftChild;   
    list = list->right;   
    parent->right = balance(list, mid+1, end);   
    return parent; 
}   

Node* balance(Node *head) {
    int size = 0;
    for (Node* n = head; n; n = n->right) ++size;
    return balance(head, 0, size-1); 
} 
link join(link a, link b) {
    if (b == 0) return a;
    if (a == 0) return b;
    insert(b, a->item);
    b->left = join(a->left, b->left);
    b->right = join(a->right, b->right);
    delete a;
    return b;
}
void insert(link &h, Item x) {
    if (h == 0) {
        h = new node(x);
        return;
    }
    if (x.key() < h->item.key()) {
        insert(h->left, x);
        rotateRight(h);
    }
    else {
        insert(h->right, x);
        rotateLeft(h);
    }
}
void rotateRight(link &h) {
    link x = h->left;
    h->left = x->right;
    x->right = h;
    h = x;
}

void rotateLeft(link &h) {
    link x = h->right;
    h->right = x->left;
    x->left = h;
    h = x;
}
public class MergeTwoBST_to_BalancedBST {

// arr1 and arr2 are the input arrays to be converted into a binary search
// structure and then merged and then balanced.
int[] arr1 = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 };
int[] arr2 = new int[] { 11, 12, 13, 14, 15, 16, 17, 18 };

BSTNode root1;
BSTNode root2;

// vector object to hold the nodes from the merged unbalanced binary search
// tree.
Vector<BSTNode> vNodes = new Vector<BSTNode>();

/**
 * Constructor to initialize the Binary Search Tree root nodes to start
 * processing. This constructor creates two trees from two given sorted
 * array inputs. root1 tree from arr1 and root2 tree from arr2.
 * 
 * Once we are done with creating the tree, we are traversing the tree in
 * inorder format, to verify whether nodes are inserted properly or not. An
 * inorder traversal should give us the nodes in a sorted order.
 */
public MergeTwoBST_to_BalancedBST() {
    // passing 0 as the startIndex and arr1.length-1 as the endIndex.
    root1 = getBSTFromSortedArray(arr1, 0, arr1.length - 1);
    System.out.println("\nPrinting the first binary search tree");
    inorder(root1); // traverse the tree in inorder format to verify whether
                    // nodes are inserted correctly or not.

    // passing 0 as the startIndex and arr2.length-1 as the endIndex.
    root2 = getBSTFromSortedArray(arr2, 0, arr2.length - 1);
    System.out.println("\nPrinting the second binary search tree");
    inorder(root2); // same here - checking whether the nodes are inserted
                    // properly or not.
}

/**
 * Method to traverse the tree in inorder format. Where it traverses the
 * left child first, then root and then right child.
 * 
 * @param node
 */
public void inorder(BSTNode node) {
    if (null != node) {
        inorder(node.getLeft());
        System.out.print(node.getData() + " ");
        inorder(node.getRight());
    }
}

/**
 * Method to traverse the tree in preorder format. Where it traverses the
 * root node first, then left child and then right child.
 * 
 * @param node
 */
public void preorder(BSTNode node) {
    if (null != node) {
        System.out.print(node.getData() + " ");
        preorder(node.getLeft());
        preorder(node.getRight());
    }
}

/**
 * Creating a new Binary Search Tree object from a sorted array and
 * returning the root of the newly created node for further processing.
 * 
 * @param arr
 * @param startIndex
 * @param endIndex
 * @return
 */
public BSTNode getBSTFromSortedArray(int[] arr, int startIndex, int endIndex) {
    if (startIndex > endIndex) {
        return null;
    }

    int middleIndex = startIndex + (endIndex - startIndex) / 2;
    BSTNode node = new BSTNode(arr[middleIndex]);
    node.setLeft(getBSTFromSortedArray(arr, startIndex, middleIndex - 1));
    node.setRight(getBSTFromSortedArray(arr, middleIndex + 1, endIndex));
    return node;
}

/**
 * This method involves two operation. First - it adds the nodes from root1
 * tree to root2 tree, and hence we get a merged root2 tree.Second - it
 * balances the merged root2 tree with the help of a vector object which can
 * contain objects only of BSTNode type.
 */
public void mergeTwoBinarySearchTree() {
    // First operation - merging the trees. root1 with root2 merging should
    // give us a new root2 tree.
    addUtil(root1);
    System.out.println("\nAfter the root1 tree nodes are added to root2");
    System.out.println("Inorder Traversal of root2 nodes");
    inorder(root2); // inorder traversal of the root2 tree should display
                    // the nodes in a sorted order.

    System.out.println("\nPreorder traversal of root2 nodes");
    preorder(root2);

    // Second operation - this will take care of balancing the merged binary
    // search trees.
    balancedTheMergedBST();
}

/**
 * Here we are doing two operations. First operation involves, adding nodes
 * from root2 tree to the vector object. Second operation involves, creating
 * the Balanced binary search tree from the vector objects.
 */
public void balancedTheMergedBST() {
    // First operation : adding nodes to the vector object
    addNodesToVector(root2, vNodes);
    int vSize = vNodes.size();

    // Second operation : getting a balanced binary search tree
    BSTNode node = getBalancedBSTFromVector(vNodes, 0, vSize - 1);
    System.out
            .println("\n********************************************************");
    System.out.println("After balancing the merged trees");
    System.out.println("\nInorder Traversal of nodes");
    inorder(node); // traversing the tree in inoder process should give us
                    // the output in sorted order ascending
    System.out.println("\nPreorder traversal of root2 nodes");
    preorder(node);
}

/**
 * This method will provide us a Balanced Binary Search Tree. Elements of
 * the root2 tree has been added to the vector object. It is parsed
 * recursively to create a balanced tree.
 * 
 * @param vNodes
 * @param startIndex
 * @param endIndex
 * @return
 */
public BSTNode getBalancedBSTFromVector(Vector<BSTNode> vNodes,
        int startIndex, int endIndex) {
    if (startIndex > endIndex) {
        return null;
    }

    int middleIndex = startIndex + (endIndex - startIndex) / 2;
    BSTNode node = vNodes.get(middleIndex);
    node.setLeft(getBalancedBSTFromVector(vNodes, startIndex,
            middleIndex - 1));
    node.setRight(getBalancedBSTFromVector(vNodes, middleIndex + 1,
            endIndex));

    return node;
}

/**
 * This method traverse the tree in inorder process and adds each node from
 * root2 to the vector object vNodes object only accepts objects of BSTNode
 * type.
 * 
 * @param node
 * @param vNodes
 */
public void addNodesToVector(BSTNode node, Vector<BSTNode> vNodes) {
    if (null != node) {
        addNodesToVector(node.getLeft(), vNodes);
        // here we are adding the node in the vector object.
        vNodes.add(node);
        addNodesToVector(node.getRight(), vNodes);
    }
}

/**
 * This method traverse the root1 tree in inorder process and add the nodes
 * in the root2 tree based on their value
 * 
 * @param node
 */
public void addUtil(BSTNode node) {
    if (null != node) {
        addUtil(node.getLeft());
        mergeToSecondTree(root2, node.getData());
        addUtil(node.getRight());
    }
}

/**
 * This method adds the nodes found from root1 tree as part it's inorder
 * traversal and add it to the second tree.
 * 
 * This method follows simple Binary Search Tree inserstion logic to insert
 * a node considering the tree already exists.
 * 
 * @param node
 * @param data
 * @return
 */
public BSTNode mergeToSecondTree(BSTNode node, int data) {

    if (null == node) {
        node = new BSTNode(data);
    } else {
        if (data < node.getData()) {
            node.setLeft(mergeToSecondTree(node.getLeft(), data));
        } else if (data > node.getData()) {
            node.setRight(mergeToSecondTree(node.getRight(), data));
        }
    }

    return node;
}

/**
 * 
 * @param args
 */
public static void main(String[] args) {
    MergeTwoBST_to_BalancedBST mergeTwoBST = new MergeTwoBST_to_BalancedBST();
    mergeTwoBST.mergeTwoBinarySearchTree();
  }
}
public class BSTNode {

BSTNode left, right;
int data;

/* Default constructor */
public BSTNode() {
    left = null;
    right = null;
    data = 0;
}

/* Constructor */
public BSTNode(int data) {
    left = null;
    right = null;
    this.data = data;
}

public BSTNode getLeft() {
    return left;
}

public void setLeft(BSTNode left) {
    this.left = left;
}

public BSTNode getRight() {
    return right;
}

public void setRight(BSTNode right) {
    this.right = right;
}

public int getData() {
    return data;
}

public void setData(int data) {
    this.data = data;
  }
}