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

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

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

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

    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

# 省略剩下的树构建和测试代码

转载于:https://www.cnblogs.com/fengyc/p/6731237.html

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是用 C 语言实现将二叉排序树转换有序双向链表的代码: ```c #include <stdio.h> #include <stdlib.h> // 定义二叉排序树的结构体 struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; }; // 定义双向链表的结构体 struct ListNode { int val; struct ListNode *prev; struct ListNode *next; }; // 将二叉排序树转换有序双向链表 void ConvertBSTToDoubleList(struct TreeNode* root, struct ListNode **head) { if (root == NULL) { return; } static struct ListNode* prev = NULL; // 定义一个静态变量 prev,用于记录前一个节点的指针 ConvertBSTToDoubleList(root->left, head); // 递归遍历左子树 struct ListNode* node = (struct ListNode*)malloc(sizeof(struct ListNode)); // 创建新的链表节点 node->val = root->val; node->prev = prev; // 将当前节点的前驱指针指向前一个节点 if (prev != NULL) { prev->next = node; // 将前一个节点的后继指针指向当前节点 } prev = node; // 更新 prev 指针为当前节点 if (*head == NULL) { *head = node; // 如果当前节点是双向链表的头节点,更新 head 指针 } ConvertBSTToDoubleList(root->right, head); // 递归遍历右子树 } // 释放二叉树的内存 void FreeBinaryTree(struct TreeNode* root) { if (root == NULL) { return; } FreeBinaryTree(root->left); FreeBinaryTree(root->right); free(root); } // 释放双向链表的内存 void FreeDoubleList(struct ListNode* head) { struct ListNode* p = head; while (p != NULL) { struct ListNode* tmp = p; p = p->next; free(tmp); } } int main() { // 从键盘输入若干个数,构造二叉排序树 int val; struct TreeNode* root = NULL; while (scanf("%d", &val) != EOF) { struct TreeNode* node = (struct TreeNode*)malloc(sizeof(struct TreeNode)); node->val = val; node->left = NULL; node->right = NULL; if (root == NULL) { root = node; } else { struct TreeNode* p = root; while (1) { if (val < p->val) { if (p->left == NULL) { p->left = node; break; } else { p = p->left; } } else { if (p->right == NULL) { p->right = node; break; } else { p = p->right; } } } } } // 将二叉排序树转换有序双向链表,并输出各个节点的值 struct ListNode* head = NULL; ConvertBSTToDoubleList(root, &head); struct ListNode* p = head; while (p != NULL) { printf("%d ", p->val); p = p->next; } // 释放内存 FreeBinaryTree(root); FreeDoubleList(head); return 0; } ``` 使用以上代码,可以从键盘输入若干个数,构造二叉排序树,然后将其转换有序双向链表,并按顺序输出各个节点的值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值