【问题标题】:Flatten binary search to in order singly linked list [C]将二分查找展平为单链表 [C]
【发布时间】:2013-04-11 02:10:47
【问题描述】:

我正在尝试将二叉搜索树展平为单链表。

二叉搜索树:

      6
    /   \
   4     8
  / \     \
 1  5     11
         / 
       10

扁平化单链表:

1 -> 4 -> 5 -> 6 -> 8 -> 10 -> 11

由于某种原因,我似乎无法弄清楚这一点。

我有一个树节点的结构:

typedef stuct node {
    int key;
    struct node *left;
    struct node *right;
} Node;

我有一个函数来创建和分配内存给树节点:

Node* newNode (int key) {
    Node *new = malloc (sizeof(Node));
    new->left = NULL;
    new->right = NULL;
    new->key = key;
    return new;
}

我有一个列表节点的结构:

typedef struct list {
    int key;
    struct list* next;
} List;

我有一个创建列表节点的函数:

List* newListNode (int key) {
    List *new = malloc(sizeof(List));
    new->key = key;
    new->next = NULL;
    return new;
}

我有创建二叉搜索树、插入值等的工作函数,但现在我需要创建一个函数来将树展平为列表。

List* flattenToLL(Node* root) {
    ...
}

我似乎无法弄清楚如何将其展平为单链表。我已经看到很多其他线程和站点讨论将二叉搜索树转换为双向或循环链表,但没有关于将值复制到单链表。如果有人可以就我如何实现这一点提出建议,我将不胜感激。这是一个家庭作业,所以如果你也可以提供一个小的解释来帮助我学习,那就太好了。

【问题讨论】:

  • 查找“有序遍历”。
  • @CarlNorum 我实际上尝试使用中序遍历来实现扁平化,但我不知道在什么旁边设置列表,以及在哪里创建新的列表节点。

标签: c linked-list binary-search-tree


【解决方案1】:

这递归做起来比较简单:

  • 检查左边的节点;如果那里有东西,请将左侧展平为列表 #1
  • 检查右边的节点;如果那里有东西,请将列表的权利展平 #2
  • 用当前节点的键创建单节点列表#3
  • 按照 #1 -> #3 -> #2 的顺序连接列表
  • 返回串联列表作为结果

这里是你如何编码:

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;
}

【讨论】:

  • 非常感谢您的帮助。我试图解决它的方式是偏离目标。我什至没有想过要创建多个列表节点。
【解决方案2】:

你需要做一个中序遍历,将每个元素依次添加到列表中。

这个的伪代码是:

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.

就是这样,就这么简单。第一步,处理左子树。第二步,添加数据。第三步,处理右子树。

唯一“聪明”的一点是以使代码简洁的方式正确处理空子树。


请记住,为了获得最大效率,如果指向最终元素(尾部)的指针未缓存在某处,则附加到链表可能是一项相对昂贵的操作。这将需要为每个添加的元素找到尾部,这会将您的展平算法变成 O(n<sup>2</sup>) 之一。

由于在链表的开始处插入一个元素几乎总是O(1),因为你必须维护一个head指针,它通常是改为执行反向中序遍历更有效:

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.

这使展平操作保持在O(n)

【讨论】:

    【解决方案3】:
    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;
        }
    

    【讨论】:

    • 抱歉没有意识到你想要在链表中。对此感到抱歉
    【解决方案4】:

    如果有人感兴趣,下面是Java代码:

    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;
    }
    

    【讨论】:

      【解决方案5】:

      我们可以使用递归,为树中的每个级别构建一个链接列表,并将该列表添加到列表向量中。使用此解决方案,我们需要跟踪我们所在的级别,因此,如果我们已经有一个级别的链表,并且我们访问了访问级别上的节点,然后我们就可以添加到该列表中。

      我没有为我自己的节点类添加任何代码,因为它与问题无关,也 没有演示内存清理,但是更好的解决方案是使用 boost::shared_ptr 来处理清理。

      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<<" ";
      }
      

      【讨论】:

      • 注意:问题是关于C c 没有模板也没有迭代器。
      【解决方案6】:

      问题here 也有非递归解决方案。

      它为您提供 O(n) 时间复杂度和 O(1) 空间复杂度。使用递归解决方案,如果例如,您可能会出现堆栈溢出。你将它应用到一个大节点集的自己的输出中。

      【讨论】:

        【解决方案7】:
         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());
        
           }
        

        【讨论】:

          猜你喜欢
          • 2017-12-12
          • 2016-02-29
          • 2015-11-17
          • 1970-01-01
          • 1970-01-01
          • 2018-03-08
          • 2021-08-15
          • 2020-01-08
          相关资源
          最近更新 更多