某公司面试题,要求:
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;
}
最后,虽然感觉自己表现的很糟糕,但是在和面试官交流的过程中感觉面试官很好,一步步引导,最后得到令我自己都感到惊艳的实现,真是值!