题目

给定一个有序链表,将其转换为一个高度平衡的二叉搜索树。这里所谓的高度平衡是指每个节点的两个子树的深度差不超过1。

引言

将有序链表转换为二叉搜索树是一种经典的二叉树问题。在这个问题中,我们需要确保二叉树的高度平衡,以便于提高搜索效率。二叉搜索树的特点是,对于每个节点,它的左子树的所有节点值都小于该节点,右子树的所有节点值都大于该节点。

算法思路

  1. 找到中间节点: 为了保持树的高度平衡,我们可以通过快慢指针法找到链表的中间节点。快指针每次走两步,慢指针每次走一步,当快指针到达链表末尾时,慢指针指向的节点即为中间节点。
  2. 递归构建左右子树: 将中间节点作为根节点,然后递归地将左半部分链表转换为左子树,右半部分链表转换为右子树。
  3. 返回根节点: 递归的基本情况是当左边部分大于右边部分时,返回空节点。

代码实现

以下是C语言中将有序链表转换为二叉搜索树的代码实现:

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

// Definition for singly-linked list.
struct ListNode {
    int val;
    struct ListNode *next;
};

// Definition for a binary tree node.
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
};

struct TreeNode* sortedListToBST(struct ListNode* head) {
    if (head == NULL) {
        return NULL;
    }
    if (head->next == NULL) {
        struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode));
        root->val = head->val;
        root->left = NULL;
        root->right = NULL;
        return root;
    }

    // 快慢指针找中间节点
    struct ListNode* slow = head;
    struct ListNode* fast = head;
    struct ListNode* prev = NULL;
    while (fast != NULL && fast->next != NULL) {
        prev = slow;
        slow = slow->next;
        fast = fast->next->next;
    }

    // 中间节点作为根节点
    struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode));
    root->val = slow->val;

    // 断开链表,递归构建左右子树
    prev->next = NULL;
    root->left = sortedListToBST(head);
    root->right = sortedListToBST(slow->next);

    return root;
}

算法分析

  • 时间复杂度: 快慢指针法找到中间节点的时间复杂度是O(n),其中n是链表的长度。在每次递归调用中,我们都需要遍历链表的一部分,因此总的时间复杂度是O(nlogn)。
  • 空间复杂度: 递归调用的堆栈深度最多为log(n),因此空间复杂度是O(logn)。

示例和测试

int main() {
    // 构造有序链表: -10 -> -3 -> 0 -> 5 -> 9
    struct ListNode* head = (struct ListNode*)malloc(sizeof(struct ListNode));
    head->val = -10;
    head->next = (struct ListNode*)malloc(sizeof(struct ListNode));
    head->next->val = -3;
    head->next->next = (struct ListNode*)malloc(sizeof(struct ListNode));
    head->next->next->val = 0;
    head->next->next->next = (struct ListNode*)malloc(sizeof(struct ListNode));
    head->next->next->next->val = 5;
    head->next->next->next->next = (struct ListNode*)malloc(sizeof(struct ListNode));
    head->next->next->next->next->val = 9;
    head->next->next->next->next->next = NULL;

    struct TreeNode* root = sortedListToBST(head);
    // 此处可以编写遍历树的代码,进行验证
    return 0;
}

总结

通过快慢指针法找到链表的中间节点,然后递归地构建左右子树,我们可以将有序链表转换为一个高度平衡的二叉搜索树。这个算法的时间复杂度是O(nlogn),空间复杂度是O(logn)。在实际应用中,这种方法可以高效地构建二叉搜索树,用于快速的搜索、插入和删除操作。

标签: 编程算法, 编程算法题, 编程算法大全, 编程算法流程, 算法设计与分析, 数据结构与算法, 算法优化, 算法实现, 常见编程算法, 编程算法入门, 编程算法进阶, 编程算法精通