二叉排序树转换为有序双向链表

二叉排序树转换为有序双向链表

刚刚看到一个有意思的数据结构的问题,怎样将二叉排序树转换为有序双向链表?

假设有以下的已排序的二叉树:

    10
   8   14
 4  9 11  16

转换为

4 <=> 8 <=> 9 <=> 10 <=> 11 <=> 14 <=> 16

怎样转换为双向链表,并且只在原来的数据结构的基础上进行转换,不创建新结点。

首先,如果在可以创建新结点的前提下,那么问题无非是变成对树进行中序遍历,将遍历的结果逐个加入到链表,伪代码如下:

class Node:
    int val,
    Node left,
    Node right,

Node root = ... # 树的根节点

def traverse(Node root):
    if root->left is not None:
        traverse(root)
    add_to_list(root)
    if root->right is not None:
        traverse(root)

def add_to_list(Node n):
    ...

现在利用原来的数据结构来转换为链表(原地整理),需要进一步分析。

在原地整理的时候,需要修改指针 left 和 right 的指向,由原来指向两个子结点变成链表的前后元素,同时也注意,原地的整理的过程与中序列遍历是类似的,先整理左子树,修改节点指针,再整理右子树,再修改节点指针,使用递归的伪代码(这个地方混合了C/python,会有点费解,看下面的C实现代码)如下:

def transform(Node root, Node** head, Node** tail):
    *head = root
    *tail = root

    if root->left is not None:
        Node* head1
        Node* tail1
        transform(root->left, &head1, &tail1)
        tail1->right = root
        root->left = tail1
        *head = head1

    if root->right is not None:
        Node* head2
        Node* tail2
        transform(root->right, &head2, &tail2)
        root->right = head2
        head2->left = root
        *tail = tail2

C 语言的具体实现如下:

#include <stdio.h>
#include <stdlib.h>

/* 节点结构体 */
typedef struct _Node
{
    int value;
    struct _Node* left;
    struct _Node* right;
} Node, *PNode;


/**
 * 转换树到双向链表,得到链表头和尾节点指针
 */
void transform(PNode n, PNode* head, PNode* tail)
{
    PNode head1 = NULL;
    PNode tail1 = NULL;
    PNode head2 = NULL;
    PNode tail2 = NULL;

    *head = n;
    *tail = n;

    if (n->left != NULL)
    {
        transform(n->left, &head1, &tail1);
        *head = head1;
        tail1->right = n;
        n->left = tail1;
    }

    if (n->right != NULL)
    {
        transform(n->right, &head2, &tail2);
        *tail = tail2;
        n->right = head2;
        head2->left = n;
    }
}

/************************************************************************/

/**
 * 将值加入到树
 */
void addToTree(PNode n, int value)
{
    if (value < n->value)
    {
        if (n->left == NULL)
        {
            n->left = calloc(1, sizeof(Node));
            n->left->value = value;
        }
        else
            addToTree(n->left, value);
    }
    if (value > n->value)
    {
        if (n->right == NULL)
        {
            n->right = calloc(1, sizeof(Node));
            n->right->value = value;
        }
        else
            addToTree(n->right, value);
    }
}

int main(void)
{
    PNode tree = NULL;
    PNode head = NULL;
    PNode tail = NULL;
    PNode i = NULL;

    /* 构建树 */
    tree = calloc(1, sizeof(Node));
    tree->value = 10;
    addToTree(tree, 8);
    addToTree(tree, 4);
    addToTree(tree, 9);
    addToTree(tree, 14);
    addToTree(tree, 11);
    addToTree(tree, 16);

    /* 转换为双向链表 */
    transform(tree, &head, &tail);
    i = head;
    while (i!=NULL)
    {
        printf("%d ", i->value);
        i = i->right;
    }
    printf("\n");

    return 0;
}

使用 python 的实现由于可返回元组,代码更加简单:

class Node(object):
    def __init__(value, left=None, right=None):
        this.value = value
        this.left = left
        this.right = right

def transform(n):
    head = n;
    tail = n;

    if n.left:
        head1, tail1 = transform(n.left)
        head = head1
        tail1.right = n
        n.left = tail1

    if n.right:
        head2, tail2 = transform(n.right)
        tail = tail2
        n.right = head2
        head2.left = n

    return head, tail

# 省略剩下的树构建和测试代码
posted @ 2017-04-18 23:55  drop *  阅读(632)  评论(0编辑  收藏  举报