如何将二进制搜索树转换为双向链表?

时间:2010-09-18 17:43:51

标签: c++ data-structures linked-list

给定一个二叉搜索树,我需要将它转换为双链表(通过以Z字形顺序遍历),仅使用指向C ++中结构的指针,如下所示,

鉴于树:

                1
                |
        +-------+---------+
        |                 |
        2                 3
        |                 |
   +----+---+        +----+---+
   |        |        |        |
   4        5        6        7
   |        |        |        |
+--+--+  +--+--+  +--+--+  +--+--+
|     |  |     |  |     |  |     |
8     9  10    11 12    13 14    15

节点结构:

struct node
{
    char * data;
    node * left;
    node * right;
};

创建列表(之字形顺序):

1 <-> 3 <-> 2 <-> 4 <-> 5 <-> 6 <-> 7 <-> 15 <-> ... <-> 8

有人可以帮助我。

11 个答案:

答案 0 :(得分:4)

这是广度优先搜索算法。 Wikipedia对如何实施它有很好的解释。

在实现算法之后,创建链表应该是明智的(因为它只是将每个访问过的元素附加到列表中)

答案 1 :(得分:3)

这是一种笨拙的树遍历。我想知道有多少人真的需要在实际代码中做这样的事情。然而,这是要解决的问题......

以下是我将如何解决这个问题:

首先,当我将所需的输出与树的结构进行比较时,我注意到树的每个“级别”从上到下依次处理。首先是顶级节点,然后是所有子节点,然后是所有子节点,依此类推。因此,一个好的解决方案可能涉及一个处理一个级别的循环,同时建立一个下一级别的节点列表,用于下一次循环迭代。

接下来,这个“zig zag”顺序意味着它需要交替处理子节点的哪个方向。如果特定的迭代从左到右,那么下一次迭代必须从右到左。然后从左到右返回以进行后续迭代,依此类推。因此,在我的循环中处理一个级别并构建下一级别的列表时,它可能需要在构建下一级别的节点列表时具有某种交替行为。在偶数迭代中,列表以单向构建。在奇数迭代中,列表是以另一种方式构建的。

或者,另一种思考这一切的方法是:设计一个解决方案,可以按1,2,3,4,5,6等顺序构建结果列表。然后将该设计修改为具有锯齿形顺序。

这是否足以让您了解如何设计解决方案?

答案 2 :(得分:2)

这可能会对您有所帮助:

  1. 为树的每个级别创建单独的列表
  2. 遍历树并在遍历树时将值复制到列表
  3. 颠倒每个其他列表的顺序
  4. 连接列表

答案 3 :(得分:2)

在下面的解决方案中,我使用了两个堆栈来交替存储Levels。 假设级别0的节点将存储在堆栈1中,其名称为head1;现在弹出元素,而不会变为空并按下堆栈2中的元素。顺序即插入的左或右子项将取决于级别。并且更改每个级别的插入顺序。

node * convert_to_dll(node *p)
{   
    static  int level=0;
    push_in_stack(p,&head1);
    printf("%d\n",p->data);

    while( head1!=NULL || head2!=NULL) {
        //pop_from_queue(&headq);

        if(head1!=NULL && head2==NULL) {
            while(head1!=NULL) {
                if(level%2==0) {
                    node *p;
                    p=new node;
                    p=pop_from_stack(&head1);

                    if(p->right!=NULL) {
                        push_in_stack(p->right,&head2);
                        printf("%d\n",(p->right)->data);
                    }
                    if(p->left!=NULL)
                    {   
                        push_in_stack(p->left,&head2);
                        printf("%d\n",(p->left)->data);
                    }
                }
            }
            //traverse_stack(head2);
            level++;
        } else {
            while(head2!=NULL) {
                if(level%2!=0) {
                    node *q;
                    q=new node;
                    q=pop_from_stack(&head2);

                    if(q->left!=NULL) {
                        push_in_stack(q->left,&head1);
                        printf("%d\n",(q->left)->data);
                    }
                    if(q->right!=NULL) {
                        push_in_stack(q->right,&head1);
                        printf("%d\n",(q->right)->data);
                    }
                }
            } //traverse_stack(head2);
            level++;
        }
    }
    return p;
}

答案 4 :(得分:1)

您可以编写一个函数来在双向链表中添加节点。然后,您可以在遍历树时调用此函数。这样你就可以做到。

答案 5 :(得分:1)

嗯......这是一个艰难的。按此顺序遍历的问题是你正在做很多跳过。这在任何首先不是深度或广度的树遍历顺序中通常都是正确的。

以下是我将如何解决这种情况。从单个空的节点列表开始,首先开始遍历树深度。务必跟踪遍历的深度。

在遍历中的每个点处,记下遍历的深度并选择数组中索引处的列表。如果那里没有,请先添加。如果深度是偶数(假设root的深度为0),则将节点添加到列表的末尾。如果它很奇怪,请将其添加到开头。

遍历所有节点后,连接列表。

答案 6 :(得分:1)

为什么要使用指针?您可以将BST存储为数组A [1 ... n]。因此,A [1]将具有根,A [2]和A [3]将具有深度1的节点,等等。这是可能的,因为它是几乎完整的树,并且您知道将存在多少元素给定深度 - 即深度d处的2 ^ d(当然除了最后深度)。现在,您所要做的就是以锯齿形方式访问数组,并创建新订单的新BST(数组)。那么,你将如何以锯齿形方式遍历数组?对于任何给定的元素A [i],左边的孩子是A [2i],右边的孩子是[2i + 1]。因此,如果您当前的深度d是奇数,则遍历2 ^ d个元素,当您到达2 ^ dth元素时,转到其左边的子元素。如果您当前的深度d是偶数,则再次遍历2 ^ d个元素,但是当您到达2 ^ dth元素时,请转到其右边的子元素。将它们存储为数组而不是节点可以使您的数据结构更精简,并且您的实现更简单。

答案 7 :(得分:0)

这个(http://cslibrary.stanford.edu/109/TreeListRecursion.html)有漂亮的照片答案:)

答案 8 :(得分:0)

#include<iostream>
#include<conio.h>
using namespace std;

class TreeNode
{
public:
    int info;
    TreeNode* right;
    TreeNode* left;
    //TreeNode* parent;
    TreeNode()
    {
        info = 0;
        right = left = NULL;
    }

    TreeNode(int info)
    {
        this -> info = info;
        right = left = NULL;
    }
};

class ListNode
{
public:
    int info;
    ListNode* next;
    ListNode()
    {
        info = 0;
        next = NULL;
    }

    ListNode(int info)
    {
        this -> info = info;
        next = NULL;
    }
};

TreeNode* root = NULL;
ListNode* start;
ListNode* end;

void addTreeNode(TreeNode*);
void convertTreeToList(TreeNode*);
void printList(ListNode*);
int findDepth(TreeNode*);

int _tmain(int argc, _TCHAR* argv[])
{
    start = end = new ListNode(0);
    char choice = 'y';
    int info;
    while(choice == 'y')
    {
        cout<<"Enter the info of new node:\n";
        cin>>info;
        addTreeNode(new TreeNode(info));
        cout<<"Want to add a new node to the tree?(y/n)\n";
        cin>>choice;
    }

    cout<<"Depth of the tree is: "<<findDepth(root);

    cout<<"Converting the tree into a doubly linked list....\n";

    convertTreeToList(root);
    printList(start->next);
    cin>>choice;
    return 0;
}



void addTreeNode(TreeNode* node)
 {
     if(!root)
     {
         root = node;
     }
     else
     {
         TreeNode* currRoot = root;
         while(1)
         {
             if(node -> info >= currRoot -> info)
             {
                 if(!currRoot -> right)
                 {
                     currRoot -> right = node;
                     break;
                 }
                 else
                 {
                     currRoot = currRoot -> right;
                 }
             }
             else
             {
                 if(!currRoot -> left)
                 {
                     currRoot -> left = node;
                     break;
                 }
                 else
                 {
                     currRoot = currRoot -> left;
                 }
             }
         }
     }
 }

 void convertTreeToList(TreeNode* node)
 {
     if(node -> left != NULL)
     {
         convertTreeToList(node -> left);
     }

         end ->next = new ListNode(node -> info);
         end = end -> next;
         end -> next = start;



         if(node -> right != NULL)
     {
         convertTreeToList(node -> right);
     }

 }


 void printList(ListNode* start)
 {
     while(start != ::start)
     {
         cout<<start->info<<" -> ";
         start = start -> next;
     }
     cout<<"x";
 }

 int findDepth(TreeNode* node)
 {
     if(!node)
     {
         return 0;
     }
     else
     {
         return (max(findDepth(node -> left), findDepth(node -> right)) + 1);
     }
 }

您到达此处的链接列表是单独链接和排序的。希望您可以轻松地在此代码中进行更改,以获得双重链接列表。只需复制 - 粘贴此代码并编译它。它将正常工作。

答案 9 :(得分:0)

让我们假设二叉树的根位于0级(偶数)。连续的水平可以被认为是奇数偶数之间的交替(根的孩子处于奇数水平,他们的孩子处于平均水平等)。 对于偶数级别的节点,我们将其子节点推送到堆栈(这会启用反向遍历)。对于奇数级别的节点,我们将其子节点推送到队列(这使得能够向前遍历)。在推送子节点之后,我们删除下一个可用元素(堆栈顶部或队列前面)并递归调用通过将级别更改为奇数或甚至取决于删除的元素所在的位置来起作用。删除的元素可以插入双向链表的末尾。下面的伪代码。

// S = stack [accessible globally]
// Q = queue [accessible globally]
//    
// No error checking for some corner cases to retain clarity of original idea    
void LinkNodes(Tree *T,bool isEven,list** l)
{

     if(isEven) {
        S.push(T->right);
        S.push(T->left);
        while( !S.empty() ) {
             t = S.pop();
             InsertIntoLinkedList(l,t);
             LinkNodes(t,!isEven);
        }
     } else {
        Q.enque(T->left);
        Q.enque(T->right);
        while( !Q.empty() ) {
            t = Q.deque();
            InsertIntoLinkedList(l,t);
            LinkNodes(t,isEven);
        }
     }
}

在通话功能中:

bool isEven = true;
list *l = NULL;           
// Before the function is called, list is initialized with root element
InsertIntoLinkedList(&l,T); 

LinkNodes(T,isEven,&l);

答案 10 :(得分:-1)

/* * File: main.cpp * Author: viswesn * * Created on December 1, 2010, 4:01 PM */

struct node {

int item; 
struct node *left; 
struct node *right; 
    struct node *next; 
    struct node *prev; 
};

struct node *dlist = NULL;

struct node *R = NULL;

struct node* EQueue[10] = {'\0'};

int Etop = 0;

struct node* OQueue[10] = {'\0'};

int Otop = 0;

int level=-1;

struct node *insert(struct node *R, int item)

{

struct node *temp = NULL; 

if (R != NULL) { 
    if (item < R->item) { 
        R->left = insert(R->left, item); 
    } else { 
        R->right = insert(R->right, item); 
    } 
} else { 
    temp = (struct node *)malloc(sizeof(struct node)); 
    if (temp == NULL) { 
        return NULL; 
    } 
    temp->item = item; 
    temp->left = NULL; 
    temp->right = NULL; 
            temp->next = NULL; 
            temp->prev = NULL; 
    R = temp; 
} 
return R; 
}

void print(struct node *node)

{

if (node != NULL) { 

    print(node->left); 
    printf("%d<->", node->item); 
    print(node->right); 
} 
}

void EvenEnqueue(struct node *item) {

if (Etop > 10) { 
    printf("Issue in EvenEnqueue\n"); 
    return; 
} 
EQueue[Etop] = item; 
Etop++; 
}

void OddEnqueue(struct node *item)

{

if (Otop > 10){ 
    printf("Issue in OddEnqueue\n"); 
    return; 
} 
OQueue[Otop] = item; 
Otop++; 
}

int isEvenQueueEmpty() {

if (EQueue[0] == '\0') { 
    return 1; 
} 
return 0; 
}

int isOddQueueEmpty()

{

if (OQueue[0] == '\0') { 
    return 1; 
} 
return 0; 
}

void EvenDQueue()

{

int i = 0; 
for(i=0; i< Etop; i++) 
    EQueue[i]='\0'; 
Etop = 0; 
}

void OddDQueue()

{

int i = 0; 
for(i=0; i< Otop; i++) 
    OQueue[i]='\0'; 
Otop = 0; 
}

void addList() {

int counter = 0; 
struct node *item = NULL; 
if (level%2 == 0) { 
        /* Its Even level*/ 
        while(counter < Etop) 
        { 
            struct node *t1 = EQueue[counter]; 
            struct node *t2 = EQueue[counter+1]; 
            if ((t1!=NULL) && (t2!=NULL)) { 
                t1->next = t2; 
                t2->prev = t1; 
            } 
            counter++; 
        } 
        item = EQueue[0]; 
} else { 
        /* Its odd level */ 
        while(counter < Otop) 
        { 
            struct node *t1 = OQueue[counter]; 
            struct node *t2 = OQueue[counter+1]; 
            if ((t1!=NULL) && (t2!=NULL)) { 
                t2->next = t1; 
                t1->prev = t2; 
            } 
            counter++; 
        } 
         item = OQueue[Otop-1]; 
} 

if(dlist !=NULL) { 
    dlist->next = item; 
} 
item->prev = dlist; 
if (level%2 == 0) { 
    dlist = EQueue[Etop-1]; 
} else { 
    dlist = OQueue[0]; 
} 
}

void printTree()

{

int nodeCount = 0; 
int counter = 0; 

if (!isEvenQueueEmpty()) { 
    /* If even level queue is not empty */ 
    level++; 
    nodeCount = pow(2,level); 
            printf("["); 
    while(counter < nodeCount) { 
        if (EQueue[counter] != '\0') { 
            struct node *t = EQueue[counter];                                
            printf("%d<->", t->item); 
                            if (t->left != NULL) 
                                OddEnqueue(t->left); 
                            if (t->right != NULL) 
                                OddEnqueue(t->right);                
        } else { 
                        break; 
                    } 
        counter++; 
    } 
            addList(); 
            printf("]"); 
            EvenDQueue(); 
} 
counter = 0; 
if (!isOddQueueEmpty()){ 
            /* If odd level queue is not empty */ 
    level++; 
    nodeCount = pow(2,level); 
            printf("["); 
    while(counter < nodeCount){ 
        if (OQueue[counter] != '\0') { 
            struct node *t = OQueue[counter];                                 
            printf("%d<->", t->item); 
                            if (t->left != NULL) 
                                EvenEnqueue(t->left); 
                            if (t->right != NULL) 
                                EvenEnqueue(t->right); 
        } else { 
                        break; 
                    } 
        counter++; 
    } 
            addList(); 
            printf("]"); 
            OddDQueue(); 
} 
if (isEvenQueueEmpty() && isOddQueueEmpty()){ 
    return; 
} 
else { 
    printTree(); 
} 
}

void printLevel(struct node *node)

{

if (node == NULL) 
    return; 
EvenEnqueue(node); 
printTree(); 
    printf("\n"); 
}

void printList(struct node *item)

{

while(item!=NULL) { 
    printf("%d->", item->item); 
    item = item->next; 
} 
}

int main(int argc, char** argv) {

int a[]={20,30,40,12,2,15,18}; 
int size = sizeof(a)/sizeof(int); 
int i = 0; 

for(i=0; i< size; i++) { 
    R = insert(R, a[i]); 
} 
    printf("Inoder traversal - Binary tree\n"); 
print(R); 
printf("\n\n"); 
    printf("Level traversal - Binary tree\n"); 
printLevel(R); 
    printf("\n"); 
    printf("Double link list traversal - Binary tree\n"); 
    printList(R); 
    printf("\n"); 
return 0; 
}