单函数实现后续遍历平衡二叉树返回前驱后继双向链表

某公司面试题,要求:

1. 结点只能包含5个字段:数据域、左右孩子、前驱后继

2. 只能用一个函数实现

3. 尽可能优化


第一个发过去的可行版本:

typedef int T;
struct Node
{
    T data;
    Node* left;
    Node* right;
    Node* pre;
    Node* next;
    Node()
    {
        left = right = pre = next = NULL;
    }
    Node(T _data):data(_data)
    {
        left = right = pre = next = NULL;
    }
};

Node* getThreads(Node* root, Node*& head, Node*& tail)
{
    if(root == NULL)
    {
        head = tail = NULL;
        return NULL;
    }
    Node *lhead, *ltail, *rhead, *rtail;
    getThreads(root->left, lhead, ltail);
    getThreads(root->right, rhead, rtail);


    head = lhead;
    tail = rtail;
    if(ltail != NULL)
        ltail->next = rhead;
    else
        head = rhead;
    if(rhead != NULL)
        rhead->pre = ltail;
    else
        tail = ltail;

    if(tail != NULL){
        tail->next = root;
        root->pre = tail;
    }
    tail = root;
    if(head == NULL)
        head = root;
    return head;
}

面试官回复说让优化一下,结果我写了个stack实现(伪stack实现)

stack<Node*> stk;
Node* getThreads(Node* root, Node*& head, Node*& tail)
{
    if(root == NULL)
    {
        return NULL;
    }
    stk.push(root);
    getThreads(root->left, head, tail);
    getThreads(root->right, head, tail);
    bool flag = true;
    if(root->right == NULL)
    {
        Node* temp = stk.top();
        stk.pop();
        if(head == NULL){
            head = root;
            tail = root;
        }
        else
        {
            tail->next = temp;
            temp->pre = tail;
            tail = temp;
        }
        flag = false;
    }
    if(flag)
    {
    	tail->next = root;
    	root->pre = tail;
    	tail = root;
    }
    return head;
}

面试官貌似怒了,说这个不是数据结构的问题,提示说每次递归都是用2个链表指针,这个不好,然后我想了想,给出了如下实现

Node* getThreads(Node* root, Node*& tail)
{
    if(root == NULL)
    {
        tail = NULL;
        return NULL;
    }
    Node *lhead, *ltail, *rhead, *rtail;
    lhead = getThreads(root->left, ltail);
    rhead = getThreads(root->right, rtail);
 
    Node* head = lhead;
    tail = rtail;
    if(ltail != NULL)
        ltail->next = rhead;
    else
        head = rhead;
    if(rhead != NULL)
        rhead->pre = ltail;
    else
        tail = ltail;
 
    if(tail != NULL){
        tail->next = root;
        root->pre = tail;
    }
    tail = root;
    if(head == NULL)
        head = root;
    return head;
}

面试官受不了了,说你对二叉树的性质了解地还不够深入,为什么每次都要先得到两个链表,然后再合并呢,可不可以只用一个链表,然后每次访问结点的时候就直接加在链表后呢(真是赤裸裸的提示啊)?于是速度改了一下,想到了static

Node* getThreads(Node* root)
{
    static Node *head = NULL, *tail = NULL;
    if(root == NULL)
    {
        return NULL;
    }
    getThreads(root->left);
    getThreads(root->right);
    if(head == NULL)
    {
        head = tail = root;
    }
    else
    {
        tail->next = root;
        root->pre = tail;
        tail = root;
    }
    return head;
}
写完连我自己都感觉这个代码真是很漂亮啊,有木有,完全少了指针乱指的情况,真是太赞了!!!

发过去之后面试官就没回复了,应该就是他心中想要的那种实现。

之后回想coding部分表现很差,于是再弄了一个stack版本的实现(真的stack,非递归的),这里要用一个标记记录每个结点的左右子数是否访问过

typedef int T;
struct Node
{
    T data;
    Node* left;
    Node* right;
    Node* pre;
    Node* next;
    Node()
    {
        left = right = pre = next = NULL;
    }
    Node(T _data):data(_data)
    {
        left = right = pre = next = NULL;
    }
};
struct Tuple
{
    Node* node;
    bool flag;
    Tuple()
    {
        node = NULL;
        flag = false;
    }
    Tuple(Node* _node, bool _flag)
        :node(_node),flag(_flag)
    {
    }
};
Node* getThreads(Node* root)
{
    stack<Tuple> stk;
    Tuple tuple;
    Node *head = NULL, *tail = NULL;
    while(root != NULL || stk.empty() == false)
    {
        while(root != NULL)
        {
            stk.push(Tuple(root, false));
            root = root->left;
        }
        while(stk.empty() == false && stk.top().flag == 1)
        {
            tuple = stk.top();
            root = tuple.node;
            stk.pop();
            if(head == NULL)
            {
                head = tail = root;
            }
            else
            {
                tail->next = root;
                root->pre = tail;
                tail = root;
            }
        }
        if(stk.empty() == false)
        {
            tuple = stk.top();
            root = tuple.node;
            stk.pop();
            tuple.flag = true;
            stk.push(tuple);
            root = root->right;
        }
        else
            break;
    }
    return head;
}

最后,虽然感觉自己表现的很糟糕,但是在和面试官交流的过程中感觉面试官很好,一步步引导,最后得到令我自己都感到惊艳的实现,真是值!






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值