【问题标题】:Convert a BST to sorted doubly linked list(Debug)将 BST 转换为已排序的双向链表(调试)
【发布时间】:2012-03-07 22:35:51
【问题描述】:

这是一个将二叉搜索树转换为排序双向链表的函数。其思想是进行中序遍历,并将访问的节点放入大小为2的循环数组中。然后调整左右指针进行转换到双向链表。当前节点的右指针永远不会被修改和访问。问题出在哪里?

void TreetoQueue(node* tnode)
 {static node* arr[2]={NULL,NULL};
  static int index=0;
    if(tnode==NULL) return;
    TreetoQueue(tnode->left);
    arr[index]=tnode;        //current node
    if(arr[1]!=NULL)
      {  if(index==0) 
         {arr[1]->right=arr[0]; //modify right pointer of inorder predecessor to point to current node
         arr[0]->left=arr[1];  //modify current node's left pointer to point to inorder predecessor 
         }

       if(index==1)
       {arr[0]->right=arr[1];
       arr[1]->left=arr[0];
       }
     cout<<"index-"<<index<<"  "<<arr[0]->val<<"  "<<arr[1]->val<<"\n";
     }

  index=(index+1)%2;
  TreetoQueue(tnode->right);
  }

          _______5______
         /              \
      ___3__             6__
     /      \               \
    1       4               _9
                           /  \
                           7  10


 index-1  1  3
 index-0  4  3
 index-1  4  5
 index-0  6  5
 index-1  6  7
 index-0  9  7  
 index-1  9  10
 node->left->left->right is NULL //Intended to be 3
 node->left->right->left is NULL//intended to be 3 
 node->left->right->right is NULL//intended to be 5 

编辑:它按预期工作。只是我必须将根更改为列表的开头。我使用另一个函数来执行此操作。我可以在没有额外功能的情况下实现这一点吗?

    node* TreetoQueue2(node* root)
      {node* head=root;
       while(head->left!=NULL)
        head=head->left;
       TreetoQueue(root);
       return head;
       } 

【问题讨论】:

  • 你说if(arr[1] != NULL)。最初它声明为NULL。我看不到它在任何时候都会改变。有什么我想念的吗?
  • arr[index]=tnode 和 index=(index+1)%2.arr[1] 如您在输出中看到的那样发生变化
  • 你能解释一下你奇怪的缩进方案吗?
  • 我认为是因为索引是静态的,但我无法理解你的想法
  • 你确定你的树是你认为的那样吗?如果发布的代码收到有效的树,我看不到任何导致段错误的原因。

标签: c++ c algorithm binary-tree


【解决方案1】:

重申丹尼尔所说的,以下测试代码按预期工作(使用 g++-4.7):

#include <iostream>

using namespace std;

struct node {
        node * left;
        node * right;
        int val;
};

typedef node * node_ptr;

void TreetoQueue(node* tnode) {

        static node* arr[2]={NULL,NULL};

        static int index=0;

        if(tnode==NULL) return;

        TreetoQueue(tnode->left);

        arr[index]=tnode;        //current node

        if(arr[1]!=NULL)
        {  
                if(index==0) 
                {
                        arr[1]->right=arr[0]; //modify right pointer of inorder predecessor to point to current node
                        arr[0]->left=arr[1];  //modify current node's left pointer to point to inorder predecessor 
                }

                if(index==1)
                {
                        arr[0]->right=arr[1];
                        arr[1]->left=arr[0];
                }
                cout<<"index-"<<index<<"  "<<arr[0]->val<<"  "<<arr[1]->val<<"\n";
        }

        index=(index+1)%2;
        TreetoQueue(tnode->right);
}

int main(int argc, char *argv[]){
        node_ptr np0 = new node();
        node_ptr np1 = new node();
        node_ptr np2 = new node();
        node_ptr np3 = new node();
        node_ptr np4 = new node();
        node_ptr np5 = new node();
        node_ptr np6 = new node();
        node_ptr np7 = new node();

        np0->val = 5;
        np1->val = 3;
        np2->val = 1;
        np3->val = 4;
        np4->val = 6;
        np5->val = 9;
        np6->val = 7;
        np7->val = 10;

        np0->left = np1;
        np1->left = np2;
        np1->right = np3;

        np0->right = np4;
        np4->right = np5;

        np5->left = np6;
        np5->right = np7;


        TreetoQueue(np0);


}

【讨论】:

  • 我希望代码重新排列左右指针分别指向有序的前任和后继(形成一个双向链表),但不知何故它们保持不变
  • @rAkesH 在这里工作,指针按应有的方式进行转换。使用TreetoQueue 将树转换为双向链表后,我可以从左到右和从右到左遍历列表,给出预期的结果。问题在于您没有向我们展示的代码。
  • @DanielFischer 是的,它确实有效!我的错。现在我不得不将根更改为列表的开头,我使用辅助函数返回最左边的树节点并调用 TreetoQueue。
【解决方案2】:

我写了一个我认为更简单、更优雅的解决方案,它仍然使用递归中序遍历的概念,但不需要在每次调用中分配任何内存:

Node* Inorder(Node* _n, Node*& _listHead, Node* _lastP=NULL){
  if (_n->left)
    _lastP = Inorder(_n->left, _listHead, _lastP);
  if (_lastP){
    _lastP->right = _n;
    _n->left = _lastP;
  }else
    _listHead = _n;
  if (_n->right)
    return Inorder(_n->right, _listHead, _n);
  return _n;
}

这个想法是跟踪添加到列表中的最后一个元素 (_lastP)。正如它所写的那样,代码将破坏二叉搜索树结构,而不是一个排序的双向链表。

这是完整的代码:

#include <iostream>
using namespace std;
struct Node{
  int data;
  Node* left;
  Node* right;
  Node(int _d=0):data(_d),left(NULL),right(NULL){}
};

Node* Inorder(Node* _n, Node*& _listHead, Node* _lastP=NULL){
  if (_n->left)
    _lastP = Inorder(_n->left, _listHead, _lastP);
  if (_lastP){
    _lastP->right = _n;
    _n->left = _lastP;
  }else
    _listHead = _n;
  if (_n->right)
    return Inorder(_n->right, _listHead, _n);
  return _n;
}

Node* BSTtoSortedDoublyLinkedList(Node* _treeRoot){
  if(!_treeRoot)
    return NULL;
  Node* listHead = NULL;
  Node* listTail = Inorder(_treeRoot, listHead);
  //could make circular with following lines
  //listHead->left = listTail; listTail->right = listHead;
  return listHead;
}

int main(){
  //create our tree
  Node* root = new Node(5);
  Node* n1 = new Node(3);
  Node* n2 = new Node(1);
  Node* n3 = new Node(4);
  Node* n4 = new Node(6);
  Node* n5 = new Node(9);
  Node* n6 = new Node(7);
  Node* n7 = new Node(10);

  root->left = n1;
  n1->left = n2;
  n1->right = n3;
  root->right = n4;
  n4->right = n5;
  n5->left= n6;
  n5->right = n7;
  /*

         _______5______
        /              \
     ___3__             6__
    /      \               \
   1       4               _9
                          /  \
                          7  10
  */

  Node* linkedList = BSTtoSortedDoublyLinkedList(root);
  while(linkedList){
    cout << linkedList->data << " ";
    linkedList = linkedList->right;
  }
  return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-14
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多