数据结构——树——二叉查找树转换成排序的循环双向链表

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构——树——二叉查找树转换成排序的循环双向链表相关的知识,希望对你有一定的参考价值。

题目描述

输入一棵二叉查找树,将该二叉查找树转换成一个排序循环双向链表。
要求不能创建任何新的结点,只调整指针的指向,也不能开辟新的存储空间O(1)

 

题目分析

首先照旧我们问题的解决思路,首先简化问题。(前提你应该了解二叉查找树和双向链表)

如果没有任何的要求,那么我们自然会想到遍历整棵树然后排序出来之后重新构建一个链表即可,你想要什么样的都可以。

那么我们需要考虑的就是如何遍历?

然后慢慢复杂问题,不能新建立,那么就要在原来的基础上改,怎么改才能变过去呢?

这时,我要教你对于树的问题,有一招特别好用的就是画出来,很多问题其实画出来就容易了,只是脑袋想想除非你的记忆和几何能力很强。。。

 

画图分析

image橙色的线原来就存在,其他颜色均为后序需要添加,打叉的需要后续去除;

这次画的比较丑,见谅,但意思是这个意思,你们画画也就出来了。这边因为要求是循环链表,所以还需将1和7相连,我就不在图上说明了,怕图更乱了。

然后可能就会有人疑惑,看图我们知道怎么变指针,但是实际中如何去变呢?又不是每张图都一样有规律。

别急,现在问题还大着,我们依旧需要把问题再次转换的小一些。

首先我们想,如果只有三个元素123这样排列,那么就好办。

如果再加个4,就难了。

作为树,你考虑的时候就需要,从三方面着手,左,中,右。

当有第四个元素出现的时候,如果第四个元素在右边和3一组,已经变成了一个链表,那么只需把这个链表看作原来的3,即可变回简单的问题。

同理,看上面大图,如果6元素的左子树变成一个链表,右子树也变成一个最终需要的链表,我们只需要把他们三个连起来就行了。

那么如何把左边变成个链表呢?

同理,只要把2元素的左子树变成一个链表,右子树也变成一个链表,连起来不就行了吗?

。。。。

然后渐渐的我们就发现,我们最终需要的算法或函数有:

1、最简单的,最多3个元素的,树变成链表

2、合并链表

3、递归遍历(我们必须先处理最里面的,处理好了外面才能合并,顺着我们的思路下来,不正是递归吗?)

 

代码描述

/**
*二叉查找树转换成排序的循环双向链表 
*    创建如下形式的树 
*       6
*    2     7
*  1   4
*     3 5
*
**/ 

#include <cstdio>
#include <cstdlib> 
#include <iostream>

using namespace std;

typedef struct Node{
    int data;//数据域 
    struct Node* pLeft;//左子叶 
    struct Node* pRight;//右子叶 
}NODE, *PNODE;//NODE等价于struct Node,PNODE等价于struct Node* 

//在树中插入节点,为了创建树(迭代)
void insert_tree(PNODE root, PNODE newNode)
{
    PNODE nowNode = root;
    PNODE nextNode = root;
    
    //找到位置才停止 
    while(nextNode != NULL)
    {
        //如果要加入的元素大于当前节点,应该放到右边 
        if(newNode->data > nextNode->data)
        {
            nowNode = nextNode;
            nextNode = nextNode->pRight;
        }
        else
        {
            nowNode = nextNode;
            nextNode = nextNode->pLeft;
        }
    }
    if(newNode->data > nowNode->data)
    {
        nowNode->pRight = newNode;
    }
    else
    {
        nowNode->pLeft = newNode;
    }
} 

//创建树 
PNODE create_tree()
{
    int dataArray[7] = {6,7,2,1,4,3,5};
    PNODE root = (PNODE)malloc(sizeof(NODE));
    root->data = dataArray[0];
    root->pLeft = NULL;
    root->pRight = NULL;
    
    for(int i=1; i<=6; i++)
    {
        PNODE newNode = (PNODE)malloc(sizeof(NODE));
        newNode->data = dataArray[i];
        newNode->pLeft = NULL;
        newNode->pRight = NULL;
        insert_tree(root,newNode);
    }
    return root;
}

//连接两个链表 
PNODE connect_list(PNODE first, PNODE second)
{
    if(first == NULL)
        return second;
    if(second == NULL)
        return first;
    
    //分别取左右边的最后元素,用于形成循环和链接 
    PNODE first_last = first->pLeft;
    PNODE second_last = second->pLeft;
    
    first_last->pRight = second;
    second->pLeft = first_last;
    
    second_last->pRight = first;
    first->pLeft = second_last;
    
    return first;
}

//树-》链表 
PNODE tree_to_list(PNODE root)
{
    if(root == NULL)
        return NULL;
    
    //左边变成链表,右边变成链表,最后连起来 
    PNODE first = tree_to_list(root->pLeft);
    PNODE second = tree_to_list(root->pRight);
    
    root->pLeft = root;
    root->pRight = root;
    
    first = connect_list(first, root);
    first = connect_list(first, second);
    
    return first;
} 

//打印最终形成的链表所有元素 
void print_list(PNODE pHead)
{
    int a = pHead->data;
    while(pHead != NULL)
    {
        cout<<pHead->data<<" ";
        pHead = pHead->pRight;
        if(a == pHead->data)
            break;
    }
    cout<<endl;
    return;
}

int main() 
{
    PNODE root = NULL;
    root = create_tree();
    print_list(tree_to_list(root));
    return 0;
}

 

总结

树的题目,要注意几个点

1、如何遍历

2、把大问题转换为小问题

3、尝试利用递归解题

以上是关于数据结构——树——二叉查找树转换成排序的循环双向链表的主要内容,如果未能解决你的问题,请参考以下文章

将二叉搜索树转变成排序的双向链表

26二叉搜索树与双向链表

二叉树进阶题------二叉树的构建及遍历;二叉搜索树转换成排序双向链表;二叉树创建字符串

二叉树进阶题------二叉树的构建及遍历;二叉搜索树转换成排序双向链表;二叉树创建字符串

二叉树进阶题------二叉树的构建及遍历;二叉搜索树转换成排序双向链表;二叉树创建字符串

算法笔试