二叉排序树转换为有序双向链表
二叉排序树转换为有序双向链表
刚刚看到一个有意思的数据结构的问题,怎样将二叉排序树转换为有序双向链表?
假设有以下的已排序的二叉树:
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
# 省略剩下的树构建和测试代码