Flatten binary search to in order singly linked list [C]

怎甘沉沦 提交于 2019-12-03 08:32:31

This is relatively simple to do recursively:

  • Check the node on the left; if there is something there, flatten the left to a list #1
  • Check the node on the right; if there is something there, flatten the right to a list #2
  • Create a single-node list #3 with the key of the current node
  • Concatenate the lists in the order #1 -> #3 -> #2
  • Return the concatenated list as your result

Here is how you can code it up:

List* flattenToLL(Node* root) {
    List *list1 = (root->left) ? flattenToLL(root->left) : NULL;
    List *list2 = (root->right) ? flattenToLL(root->right) : NULL;
    List *list3 = newNode(root->key);
    // The "middle" list3 cannot be NULL; append list2 to list3
    list3->next = list2; // If list2 is NULL, it's OK
    if (!list1) return list3; // Nothing to prepend
    List *last = list1;
    while (last->next) last=last->next; // Go to the end of list1
    last->next = list3; // Append list3+list2 to the end of list1
    return list1;
}

You need to do an in-order traversal, adding each element in turn to the list.

The pseudo-code for this is:

def traverse (node, list):
    if node == NULL: return       # Ignore empty subtrees.
    traverse (node.left, list)    # Do left subtree first.
    list.append (node.data)       # Then current node.
    traverse (node.right, list)   # Then right subtree.

list = new List()                 # Create empty list.
traverse (root, list)             # Collapse tree to list.

That's it, as simple as it gets. Step 1, process the left subtree. Step 2, add the data. Step 3, process the right subtree.

The only "clever" bit is correct handling of empty subtrees in a way that makes the code succinct.


Keep in mind that, for maximum efficiency, appending to a linked list may be a relatively expensive operation if the pointer to the final element (tail) is not cached somewhere. That will entail having to find the tail for each element being added, something that will turn your flattening algorithm into an O(n2) one.

Since inserting an element at the start of a linked list is almost invariably O(1) by virtue of the fact you must maintain a head pointer, it's often more efficient to do a reverse in-order traversal instead:

def traverse (node, list):
    if node == NULL: return       # Ignore empty subtrees.
    traverse (node.right, list)   # Do right subtree first.
    list.insert (node.data)       # Then current node at list start.
    traverse (node.left, list)    # Then left subtree.

This keeps the flattening operation at O(n).

Why dont you do inorder traversal and add values to list in a way.  

public List<Integer> inorderToList(TreeNode<Integer> node, List<Integer> list) {
        if(node == null) {
            return list;
        } 
        if (node != null) {
            list = inorderToList(node.getLeft(), list);
            list.add(node.getValue());
            list = inorderToList(node.getRight(), list);
        }
        return list;
    }

Below is the Java code if someone is interested:

public static Node bTreeToLinkedList(TreeNode root) {
    Node list1 = root.getLeftChild() != null ? bTreeToLinkedList(root.getLeftChild()) : null;
    Node list2 = root.getRightChild() != null ? bTreeToLinkedList(root.getRightChild()) : null;
    Node list3 = ll.new Node((int) root.getData());

    list3.setNext(list2);
    if (list1 == null)
        return list3;

    Node last = list1;
    while (last.getNext() != null)
        last = last.getNext();
    last.setNext(list3);

    return list1;
}

We can use recurssion where we build a linked list for each level in the tree and add the list to a vector of lists. With this solution we need to keep a track of which level we are on, so if we have a linked list already for a level and we visit a node on a level visited before we can just add to that list.

I have not added any code for my own node class as its not relevant to the question, also no memory clean up is being demonstrated, however a better solution would be to use boost::shared_ptr to handle clean up.

void generateLists(vector<list<node*>* >*& lists, node* root, int level)
{
    //base case
    if(root == NULL)
        return;

    //if we have don't have a linked list at this level so create this
    if((int)lists->size() == level)
    {
        list<node*>* ls = new list<node*>();
        ls->push_back(root);
        lists->push_back(ls);
    }
    else
    {
        //re-use existing list
        list<node*>* ls = lists->at(level);
        if(ls != NULL)
            ls->push_back(root);
    }

    //in order traversal
    generateLists(lists, root->left, level+1);
    generateLists(lists, root->right, level+1);
}

int main(void)
{
    //create a test binary tree
    node root(6);
    node n2(3);
    node n3(9);
    node n4(2);
    node n5(5);
    node n6(8);
    node n7(9);

    root.left = &n2;
    root.right = &n3;
    n2.left = &n4;
    n2.right=&n5;
    n3.left=&n6;
    n3.right=&n7;

    //will hold a vector of lists for each level in the tree
    vector<list<node*>* >* lists = new vector<list<node*>* >();
    int level=0;
    generateLists(lists, &root, level);
    vector<list<node*>* >::iterator it;

    //convert each level in the tree to a single linked list
    list<node*> flattened;
    for(it = lists->begin(); it != lists->end(); it++)
    {
        list<node*>* linkedList = (*it);
        list<node*>::iterator itNode;
        for(itNode = linkedList->begin(); itNode != linkedList->end(); itNode++)
            flattened.push_back(*itNode);
    }

    //output the tree as a linked list
    list<node*>::iterator itNode;
    for(itNode = flattened.begin(); itNode != flattened.end(); itNode++)
        cerr<<(*itNode)->val<<" ";
}

There is also non-recursive solution for the problem here.

It gives you O(n) time complexity and O(1) space complexity. With recursive solution you can get stack overflow if e.g. you apply it to its own output for a big node set.

 private static BSTNode head;
 private static BSTNode tail;
 public static void inorderTraversal(BSTNode node) {
        if(node.left != null) {
            inorderTraversal(node.left);
        }
        System.out.print(node.data + " ");
        constructLinkedList(node.data);
        if(node.right != null) {
            inorderTraversal(node.right);
        }
    }

public static void constructLinkedList(int data) {
        if(head == null) {
            head = new BSTNode(data);
            head.left = null;
            tail = head;
        } else {
            BSTNode node = new BSTNode(data);
            tail.right = node;
            tail.left = null;
            tail = node;
        }
   }

   public static void linkedListToString() {
        BSTNode curr = head;
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        while(curr.right != null) {
            sb.append(curr.data).append("->");
            curr = curr.right;
        }
        if(curr.right == null)
            sb.append(curr.data).append("->NULL");
        sb.append("]");
        System.out.print(sb.toString());

   }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!