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

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

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

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

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 *  阅读(659)  评论(0)    收藏  举报