Algorithm 将二叉树转换为链表、宽度优先、恒定存储/破坏性
这不是家庭作业,我也不需要回答,但现在我变得痴迷了:) 问题是:Algorithm 将二叉树转换为链表、宽度优先、恒定存储/破坏性,algorithm,tree,binary-tree,Algorithm,Tree,Binary Tree,这不是家庭作业,我也不需要回答,但现在我变得痴迷了:) 问题是: 设计一种算法,将二叉树破坏性地展平为链表,宽度优先。好的,很简单。只要建立一个队列,然后做你必须做的事情 这就是热身。现在,用常量存储实现它(递归,如果你能用它找到答案的话,是对数存储,而不是常量) 大约一年前,我在互联网上找到了这个问题的解决方案,但现在我忘记了,我想知道:) 据我记忆所及,这个技巧涉及使用树来实现队列,利用算法的破坏性。链接列表时,也会将项目推入队列 每次尝试解决此问题时,我都会丢失节点(例如每次链接下一个
- 设计一种算法,将二叉树破坏性地展平为链表,宽度优先。好的,很简单。只要建立一个队列,然后做你必须做的事情
- 这就是热身。现在,用常量存储实现它(递归,如果你能用它找到答案的话,是对数存储,而不是常量)
struct tree_node
{
int value;
tree_node* left;
tree_node* right;
};
首先,我假设您的节点有一个指向其父节点的“parent”字段。要么就是这样,要么你需要一个堆栈,以便能够在树中向上移动(因此无法实现O(1)辅助内存需求) 在O(1)空间中有一个众所周知的有序迭代,它是迭代的。例如,假设您希望按顺序打印项目。基本上,当你遍历一棵二叉树时,你必须在任何给定的时刻,在任何给定的节点上,决定你是想向上移动(到父节点)、向左移动(到左子节点)还是向右移动。该算法的思想是根据您来自何处来做出决策:
编辑2:根据Svante可以理解的愿望,我明确建议在一些代码中使用左旋转:
#include <stdlib.h>
#include <stdio.h>
typedef struct node *node;
struct node
{
int value;
node left;
node right;
};
node new_node(int value, node left, node right)
{
node n = (node) malloc(sizeof(struct node));
n->value = value; n->left = left; n->right = right;
return n;
}
int rotate_right(node tree)
{
if(tree != NULL && tree->left != NULL)
{
node
a = tree->left->left,
b = tree->left->right,
c = tree->right;
int tmp = tree->value;
tree->value = tree->left->value;
tree->left->value = tmp;
tree->left->left = b;
tree->left->right = c;
tree->right = tree->left;
tree->left = a;
return 1;
}
return 0;
}
生成的树是一个已排序的链表,其中列表的下一个指针是树中的右指针。最后,这里是一个测试程序:
int main()
{
node t =
new_node(4,
new_node(2, NULL, new_node(3, NULL, NULL)),
new_node(8, new_node(5, NULL, NULL), NULL));
convert_to_list(t);
for(; t != NULL; t = t->right)
printf("%d, ", t->value);
return 0;
}
好吧,我现在不太清楚这在这种情况下有什么帮助,但它可能会给你一个线索。有一种称为“指针反转”的技术,用于迭代遍历树,而无需使用堆栈/队列来存储指针——它主要用于低内存开销的垃圾收集器。这背后的思想是,当您遍历到节点的子节点时,您将指向子节点的指针链接回父节点,以便在完成该节点时知道返回的位置。这样,通常保存在堆栈/队列中的回溯信息现在嵌入到树本身中
我通过一个例子发现了以下内容(不幸的是,谷歌上没有更好的东西)。这里的示例演示了如何在没有额外存储的情况下遍历二叉树。我认为我们不需要父指针。归纳地假设级别0到k-1加上哨兵节点已转换为左子指针上的单链表,其右子指针指向级别k的节点。遍历列表,依次抓取每个“右子节点”(级别k节点),并将其插入列表的末尾,覆盖右指针,该指针随即将被覆盖的左子节点一起出现。当我们到达列表的起始端时,我们将归纳假设扩展到k+1 编辑:代码
#include <cstdio>
struct TreeNode {
int value;
TreeNode *left;
TreeNode *right;
};
// for simplicity, complete binary trees with 2^k - 1 nodes only
void Flatten(TreeNode *root) {
TreeNode sentinel;
sentinel.right = root;
TreeNode *tail = &sentinel;
while (true) {
TreeNode *p = &sentinel;
TreeNode *old_tail = tail;
while (true) {
if ((tail->left = p->right) == NULL) {
return;
}
tail = p->right;
p->right = p->right->left;
if (p == old_tail) {
break;
}
p = p->left;
}
}
}
int main() {
const int n = 31;
static TreeNode node[1 + n];
for (int i = 1; i <= n; ++i) {
node[i].value = i;
if (i % 2 == 0) {
node[i / 2].left = &node[i];
} else {
node[i / 2].right = &node[i];
}
}
Flatten(&node[1]);
for (TreeNode *p = &node[1]; p != NULL; p = p->left) {
printf("%3d", p->value);
}
printf("\n");
}
#包括
树状结构{
int值;
TreeNode*左;
TreeNode*对;
};
//为简单起见,只使用2^k-1个节点的完整二叉树
空洞展平(树形节点*根){
树状哨兵;
sentinel.right=根;
TreeNode*tail=&sentinel;
while(true){
TreeNode*p=&sentinel;
TreeNode*旧_尾=尾;
while(true){
如果((尾部->左=p->右)==NULL){
返回;
}
尾部=p->右侧;
p->righ
#include <cstdio>
struct TreeNode {
int value;
TreeNode *left;
TreeNode *right;
};
// for simplicity, complete binary trees with 2^k - 1 nodes only
void Flatten(TreeNode *root) {
TreeNode sentinel;
sentinel.right = root;
TreeNode *tail = &sentinel;
while (true) {
TreeNode *p = &sentinel;
TreeNode *old_tail = tail;
while (true) {
if ((tail->left = p->right) == NULL) {
return;
}
tail = p->right;
p->right = p->right->left;
if (p == old_tail) {
break;
}
p = p->left;
}
}
}
int main() {
const int n = 31;
static TreeNode node[1 + n];
for (int i = 1; i <= n; ++i) {
node[i].value = i;
if (i % 2 == 0) {
node[i / 2].left = &node[i];
} else {
node[i / 2].right = &node[i];
}
}
Flatten(&node[1]);
for (TreeNode *p = &node[1]; p != NULL; p = p->left) {
printf("%3d", p->value);
}
printf("\n");
}
1
/ \
2 3
/ \ / \
4 5 6 7
/ \ / \ / \ / \
8 9 A B C D E F
head
v
1
/ \
tail 2 4
v / \ / \
3 5 8 9
/ \ / \
6 7 A B
/ \ / \
C D E F
head
v
1
/ \
2 6
/ \ / \
3 7 C D
/ \ / \
4 8 E F
/ \
tail > 5 9
/ \
A B
head
v
1
/ \
2 B
/ \
3 C
/ \
4 D
/ \
5 E
/ \
6 F
/
7
/
8
/
9
/
tail > A
(defclass node ()
((left :accessor left)
(right :accessor right)
(value :accessor value)))
(defmacro swap (a b)
`(psetf ,a ,b
,b ,a))
(defun flatten-complete-tree (root)
(loop for tail = (and root (left root)) then (left tail)
while tail
do (swap (left tail) (right root))
(loop for bubble-to = root then (left bubble-to)
for bubble-from = (left bubble-to)
until (eq bubble-from tail)
do (swap (right bubble-to) (right bubble-from))))
root)
(defun flatten-tree (root)
(loop for head = (loop for x = (or head root) then (left x)
do (when (and x (null (left x)))
(swap (left x) (right x)))
until (or (null x) (right x))
finally (return x))
for tail = (and head (left head)) then (left tail)
while head
do (swap (left tail) (right head))
(loop for bubble-to = head then (left bubble-to)
for bubble-from = (left bubble-to)
until (eq bubble-from tail)
do (swap (right bubble-to) (right bubble-from))))
root)
public static Tree<T> Flatten(Tree<T> t, Tree<T> u = null)
{
if (t == null) return u;
t.R = Flatten(t.L, Flatten(t.R, u));
t.L = null;
return t;
}
// Flatten a tree into place in BFS order using O(1) space and O(n) time.
// Here is an example of the transformation (the top-row indicates the
// flattened parts of the tree.
//
// a
// |---.
// b c
// |-. |-.
// d e f g
//
// becomes
//
// a-b-c
// | | |-.
// d e f g
//
// becomes
//
// a-b-c-d-e-f-g
//
public static void FlattenBFS(Tree<T> t)
{
var a = t; // We "append" newly flattened vertices after 'a'.
var done = (t == null);
while (!done)
{
done = true;
var z = a; // This is the last vertex in the flattened part of the tree.
var i = t;
while (true)
{
if (i.L != null)
{
var iL = i.L;
var iLL = iL.L;
var iLR = iL.R;
var aR = a.R;
i.L = iLL;
a.R = iL;
iL.L = iLR;
iL.R = aR;
a = iL;
done &= (iLL == null) & (iLR == null);
}
if (i == z)
{
break; // We've flattened this level of the tree.
}
i = i.R;
}
a = (a.R ?? a); // The a.R item should also be considered flattened.
}
}
temp=root;
struct node*getleftmost(struct node* somenode)
{
while(somenode->left)
somenode=somenode->left;
return somenode;
}
while(temp)
{
if(temp->right){
(getletfmost(temp))->left=temp->right;
temp->right=NULL;}
temp=temp->left;
}
struct TreeNode
{
TreeNode(int in) : data(in)
{
left = nullptr;
right = nullptr;
}
int data;
TreeNode* left;
TreeNode* right;
};
//Converts left pointer to prev , right pointer to next
// A tree which is like 5
// 11 12
//will be converted to double linked list like 5 -> 12 -> 11
void finalize(TreeNode* current, TreeNode* parent)
{
if (parent == nullptr)
{
current->left = nullptr;
return;
}
if (parent->left == current)
{
if (parent->right == nullptr)
{
parent->right = current;
current->left = parent;
}
current->left = parent->right;
}
else
{
current->left = parent;
parent->right = current;
current->right = parent->left;
}
}
void traverser(TreeNode* current, TreeNode* parent)
{
if (current->left != nullptr)
traverser(current->left, current);
if (current->right != nullptr)
traverser(current->right, current);
finalize(current, parent);
}
void start(TreeNode* head)
{
if (head == nullptr || (head->left == nullptr && head->right == nullptr))
return;
traverser(head, nullptr);
}
int main()
{
TreeNode* n1 = new TreeNode(5);
TreeNode* n2 = new TreeNode(11);
TreeNode* n3 = new TreeNode(12);
n1->left = n2;
n1->right = n3;
start(n1);
}