给定二叉树,如何从左到右加入每个级别的节点。 假设第3级有5个节点,从左到右连接所有节点。
我不需要任何人为此编写代码..但只是一种有效的算法。
由于
答案 0 :(得分:5)
想法是:
1.用BFS遍历树。
2.当您进行遍历时,您将链接下一级别的节点 - 如果节点具有左侧和右侧节点,则您将从左向右链接。如果节点有下一个节点,则将当前节点的最右边的子节点链接到下一节点的最左边的子节点。
public void BreadthFirstSearch(Action<Node> currentNodeAction)
{
Queue<Node> q = new Queue<Node>();
q.Enqueue(root);
while (q.Count != 0)
{
Node current = q.Dequeue();
if (currentNodeAction != null)
currentNodeAction(current);
if (current.left != null) q.Enqueue(current.left);
if (current.right != null) q.Enqueue(current.right);
}
}
private void Linker(Node node)
{
Link(node.left, node.right);
if (node.next != null)
Link(node.right ?? node.left, node.next.left ?? node.next.right);
}
private void Link(Node node1, Node node2)
{
if (node1 != null && node2 != null)
node1.next = node2;
}
public void LinkSameLevel()
{
BreadthFirstSearch(Linker);
}
答案 1 :(得分:4)
创建链接列表的向量。 DFS会跟踪您的级别,并且对于您找到的每个节点,将其添加到级别的链接列表中。 这将在O(n)中运行,这是最佳的。
这是你想要做的吗?
答案 2 :(得分:2)
这不是问题的直接答案,可能不适用于您的情况。但是,如果您可以控制二叉树的创建和维护,那么在构建/更新树时维护链接可能会更有效。
如果你在每个级别都保留了左右两个指针,那么维护它们就会“简单”(总是很容易在其他人做这项工作时说出这个词)。在给定级别插入新节点时,您可以从父节点信息中知道它的直接兄弟节点。您可以调整所涉及的三个节点的左右指针(假设不在树的边缘)。同样,在删除节点时,只需更新要删除的节点的兄弟节点的左右指针。改变它们以指向彼此。
答案 3 :(得分:1)
如果你想同时制作所有的行列表,我同意Thomas Ahle的回答。您似乎只对列出一个特定行的列表感兴趣。
假设您有一棵巨树,但您只想链接第5行。访问第5行下面的任何节点显然没有意义。所以只需做一个早期终止的DFS。不幸的是,您仍然需要遍历列表中每个节点的所有祖先。
但这是个好消息。如果你有一个完美的二叉树(每个节点除最后一行之外都会分两次),那么第一行将有1个,第二个2,第三个4,第四个8和第五个16。因此还有更多最后一行(16)上的节点比之前的所有节点(1 + 2 + 4 + 8 = 15),所以搜索所有的祖先仍然只是O(n),其中n是节点中的节点数行。
另一方面,最坏的情况是让第五行由单个节点组成,其上面有一个完整的二叉树。然后你仍然需要搜索所有15个祖先只是为了将那个节点放在列表中。
因此,虽然在不修改数据结构的情况下,此算法确实是您唯一的选择,但其效率完全依赖于将行与较高行进行比较的方式。
答案 4 :(得分:0)
#include <queue>
struct Node {
Node *left;
Node *right;
Node *next;
};
/** Link all nodes of the same level in a binary tree. */
void link_level_nodes(Node *pRoot)
{
queue<Node*> q;
Node *prev; // Pointer to the revious node of the current level
Node *node;
int cnt; // Count of the nodes in the current level
int cntnext; // Count of the nodes in the next level
if(NULL == pRoot)
return;
q.push(pRoot);
cnt = 1;
cntnext = 0;
prev = NULL;
while (!q.empty()) {
node = q.front();
q.pop();
/* Add the left and the right nodes of the current node to the queue
and increment the counter of nodes at the next level.
*/
if (node->left){
q.push(node->left);
cntnext++;
}
if (node->right){
q.push(node->right);
cntnext++;
}
/* Link the previous node of the current level to this node */
if (prev)
prev->next = node;
/* Se the previous node to the current */
prev = node;
cnt--;
if (0 == cnt) { // if this is the last node of the current level
cnt = cntnext;
cntnext = 0;
prev = NULL;
}
}
}
答案 5 :(得分:0)
我通常做的解决这个问题的方法是我做一个简单的inorder遍历。
我使用构造函数初始化我的树,该构造函数为每个节点提供级别或列值。因此我的头脑处于0级。
public Node(int d)
{
head=this;
data=d;
left=null;
right=null;
level=0;
}
现在,如果在遍历中,我左转或右转,我只需使用水平指示器进行遍历。对于每个级别标识符,我可以在节点向量中创建链接列表。
答案 6 :(得分:0)
可以使用不同的方法来解决此问题。其中一些想到的是 -
1)使用级别顺序遍历或BFS
我们可以修改队列条目以包含节点级别。因此队列节点将包含指向树节点和整数级别的指针。当我们deque一个节点时,我们可以检查出列节点的级别是否相同我们可以设置右指针指向它。
该方法的时间复杂度为O(n)。
2)如果我们有完整的二叉树,我们可以扩展Pre-Order遍历。在这个方法中,我们将在子项之前设置父项的右指针 该方法的时间复杂度为O(n)。
3)在不完整的二叉树的情况下,我们可以通过遍历第一个根然后右指针来修改方法(2)然后向左,这样我们就可以确保第i级的所有节点都有正确的指针集,在i +级之前1个节点。 该方法的时间复杂度为O(n ^ 2)。
答案 7 :(得分:0)
private class Node
{
public readonly Node Left;
public readonly Node Right;
public Node Link { get; private set; }
public void Run()
{
LinkNext = null;
}
private Node LinkNext
{
get
{
return Link == null ? null : (Link.Left ?? Link.Right ?? Link.LinkNext);
}
set
{
Link = value;
if (Right != null)
Right.LinkNext = LinkNext;
if (Left != null)
Left.LinkNext = Right ?? LinkNext;
}
}
}
答案 8 :(得分:0)
在广度优先搜索中保留深度数组。
vector<forward_list<index_t>> level_link(MAX_NODES);
index_t fringe_depth = 0;
static index_t depth[MAX_NODES];
memset(depth,0,sizeof(depth));
depth[0] = 0;
现在,当出队时深度发生变化时,您将全部链接!
explored[0] = true;
static deque<index_t> fringe;
fringe.clear();
fringe.push_back(0); // start bfs from node 0
while(!fringe.empty()) {
index_t xindex = fringe.front();
fringe.pop_front();
if(fringe_depth < depth[xindex]) {
// play with prev-level-data
fringe_depth = depth[xindex];
}
现在我们具有边缘深度,因此我们可以进行水平链接。
level_link[fringe_depth].push_front(xindex);
for(auto yindex : nodes[xindex].connected) {
if(explored[yindex])
continue;
explored[yindex] = true;
depth[yindex] = depth[xindex] + 1;
fringe.push_back(yindex);
}
}