问题
How can a sorted doubly linked list be converted to a balanced binary search tree.
I was thinking of doing this the same way as converting an array to a balanced BST. Find the centre and then recursively convert the left part and the right part of the DLL. For example,
1 2 3 4 5
=> 1 2 (3) 4 5
=>
3
/ \
2 4
/ \
1 5
This is leads to the recurrence T(n) = 2T(n/2) + O(n). O(n) is for finding the centre. The time complexity is therefore O(nlogn). I was wondering if there is an algorithm that does this in O(n).
回答1:
Yes there is O(n) solution. Note that an in-order traversal on a BST, is iterating the elements in the desired order, so just do an inorder traversal on an initially empty tree of size n, and fill it with elements in the list. [The i'th element you insert to the tree in your traversal, is the i'th element in the list].
At the end of the answer I added how to create an empty balanced tree in O(n)
.
pseudocode: [assuming |list| == |tree|]
global current <- null
fillTree(tree,list):
current <- list.head
fillTree(tree)
fillTree(tree):
if tree == null:
return
fillTree(tree.left)
//in-order traversal: we set the value after setting left, and before calling right
tree.val <- current.val
current <- current.next
fillTree(tree.right)
Complexity is trivially O(n)
, since there is excactly one iteration for each vertex of the tree, and each iteration is O(1).
EDIT:
You can create an empty balanced tree, by simply building an empty complete tree(*), it is balanced and building it is O(n).
(*)A complete binary tree is a binary tree in which every level, except possibly the last, is completely filled.
回答2:
almost 4 years late. but here comes my functional solution. following is my code in haskell, complexity is also O(n)
:
import Data.List hiding (insert)
data Color = R | B deriving Show
data RBTree a = RBEmpty | RBTree { color :: Color
, ltree :: RBTree a
, nod :: a
, rtree :: RBTree a } deriving Show
fromOrdList :: Ord e => [e] -> RBTree e
fromOrdList [] = empty
fromOrdList lst =
let (res, _) = _fol lst $ length lst
in res
where _fol :: (Ord e, Integral a) => [e] -> a -> (RBTree e, Maybe (e, [e]))
_fol l 0 = (empty, uncons l)
_fol (h:l) 1 = (RBTree B empty h empty, uncons l)
_fol (h1:h2:l) 2 = (RBTree B (RBTree R empty h1 empty) h2 empty, uncons l)
_fol (h1:h2:h3:l) 3 = (RBTree B (RBTree R empty h1 empty) h2 (RBTree R empty h3 empty), uncons l)
_fol l n =
let mid = n `div` 2
(ltr, Just (rt, tl)) = _fol l mid
(rtr, mayremain) = _fol tl (n - 1 - mid)
in (RBTree B ltr rt rtr, mayremain)
which is actually a part of my personal practise: https://github.com/HuStmpHrrr/PFDSPractise/blob/master/src/Tree/RBTree.hs#L97
回答3:
Look at my implementation of recursive insertion (c#). There are T(n) = 2*T(n/2) + O(1). O(1) is for finding the centre: (l+r)/2. So complicity is O(n)
public class Tree<T>
{
public class TreeNode<T>
{
public TreeNode<T> Right { get; set; }
public TreeNode<T> Left { get; set; }
public T Data { get; set; }
}
public Tree()
{
Root = new TreeNode<T>();
}
public TreeNode<T> Root { get; set; }
private void InsertSortedListRec(IList<T> items, TreeNode<T> curNode, int l, int r)
{
var mid = (l + r)/2;
curNode.Data = items[mid];
if (mid - 1 >= l)
{
curNode.Left = new TreeNode<T>();
InsertSortedListRec(items, curNode.Left, l, mid - 1);
}
if (mid + 1 <= r)
{
curNode.Right = new TreeNode<T>();
InsertSortedListRec(items, curNode.Right, mid + 1, r);
}
}
public void InsertSortedList(IList<T> items)
{
InsertSortedListRec(items, Root, 0, items.Count - 1);
}
}
I assume that we have indexed array (we can convert linked list to array O(n))
来源:https://stackoverflow.com/questions/7874517/converting-a-sorted-doubly-linked-list-to-a-bst