拥有原始和"最终" / 结果树。我想比较这些树和"再现"这些步骤将具有相同的结果。
现实生活中的例子:在数据库中拥有原始树。工作人员已准备好更改(在App中生成新的结果树),现在我们需要更新数据库。我们无法删除数据库和重新上载,因为可能还有数据尚未生成。
班级/表格定义:
class TreeNode
{
public string Text { get; set; }
public TreeNode Parent { get; set; }
/* some other properties */
}
示例树:
Origin Result
|A |A
| -1 | -2
| -2 |C
|B | -3
| -5 |D
| --£ | -1
|C | --£
|F | -5
| -7 |E
|H | -6
|G
| -4
|H
我期望有一个算法,当添加,删除或移动时,我将被允许处理该算法
重要提示:具有其他父级的对象不应该已删除且已添加,而应仅在其他父级下移动!删除会导致数据丢失。
示例:
Mark B as removed
Mark F as removed
Add D
Add E
Add G
Move 1 under D
Move 5 under D
Mark 7 as removed
Add 3 under C
Add 6 under E
Add 4 under G
Move £ under 1
Removed 7
Removed F
Removed B
自己的解决方案
我使用 Win-Forms 和 TreeView 创建了示例。我的算法仅适用于每个级别的基础(例如,从A移动到D),但不能跨越。元素是第一个被删除的市场,最后被移除。
代码:
//Recursive loop to find all nodes in Nth level
private IEnumerable<TreeNode> getNodesOnLevel(TreeNodeCollection aCollection, int aLevel)
{
var lResultTreeNodeCol = new List<TreeNode>();
if (aLevel == 1)
return aCollection.Cast<TreeNode>();
foreach(TreeNode nNode in aCollection)
{
lResultTreeNodeCol.AddRange(getNodesOnLevel(nNode.Nodes, aLevel - 1));
}
return lResultTreeNodeCol;
}
//Called once
public void UpdateTrees(TreeNodeCollection aCollectionA, TreeNodeCollection aCollectionB)
{
List<TreeNode> lRemoved = new List<TreeNode>();
for (int i = 1; UpdateWithLevel(aCollectionA, aCollectionB, i, ref lRemoved) > 0; i++)
{
}
var lRem = lRemoved.LastOrDefault();
do
{
W($"Removed {lRem.Text}");
lRemoved.Remove(lRem);
} while ((lRem = lRemoved.LastOrDefault()) != null);
}
//Called per level
private int UpdateWithLevel(TreeNodeCollection aCollectionA, TreeNodeCollection aCollectionB, int level, ref List<TreeNode> aRemoved)
{
int lNumOfUpdates = 0;
var colA = getNodesOnLevel(aCollectionA, level);
var colB = getNodesOnLevel(aCollectionB, level);
//Search Original collection, compare to Result collection
foreach (TreeNode nodeA in colA)
{
//Find nodeA in Result collection
var lNodeAinColB = colB.FirstOrDefault((a) => a.Text == nodeA.Text);
if(lNodeAinColB == null) //NodeA not found in result collection - delete
{
aRemoved.Add(nodeA);
W($"Mark {nodeA.Text} as removed");
lNumOfUpdates++;
}
else if((lNodeAinColB.Parent?.Text ?? "") != (nodeA.Parent?.Text ?? "")) //NodeA exists in Result collection, different parrent -> must be moved
{
W($"Move {nodeA.Text} under {lNodeAinColB.Parent.Text}");
lNumOfUpdates++;
}
}
//Search Result collection, if Original collection does not have nodeB, we must create it (add)
foreach (TreeNode nodeB in colB)
{
if (!colA.Contains(nodeB, new TestNodeEquality()))
{
W($"Add {nodeB.Text}" + ((nodeB.Parent != null)?$" under {nodeB.Parent.Text}":""));
lNumOfUpdates++;
}
}
return lNumOfUpdates;
}
我还没有发现任何适合我的问题的主题,也没有找到有价值的资源。我真的很想避免重新发明轮子。
问题(S):
是否存在&amp;工作alghoritm(名称/参考)?什么是这种称为Alghorithms / action(树差/合并/查找/ ......)?
我可以用任何方式优化alghoritm吗?
答案 0 :(得分:3)
我不认为你需要一些复杂的递归算法。只需将结果节点放入名称 - 父词典并检查:
Dictionary还为搜索节点提供了O(1),因此这也是一种优化。这与<div class="projects">
<div class="art-project1">
<img class="img-img" src="https://static.standard.co.uk/s3fs-public/thumbnails/image/2014/12/16/08/138188934.png" width="600" height="400" />
<p class="project-description1">Get Involved</p>
</div>
操作相关,这是快速设置操作。
代码:
Except
答案 1 :(得分:1)
我没有C#环境,所以我想我可以在Python中实现它 - 他们称之为可执行伪代码,对吧? ;)
def node(id, children=[]):
assert all(isinstance(child, dict) for child in children)
return {'id': id, 'children': children}
tree1 = [
node('a', [
node('1'),
node('2'),
]),
node('b', [
node('5', [
node('*'),
]),
]),
node('c'),
node('f', [
node('7'),
]),
node('h'),
]
tree2 = [
node('a', [
node('2'),
]),
node('c', [
node('3'),
]),
node('d', [
node('1', [
node('*'),
]),
node('5'),
]),
node('e', [
node('6'),
]),
node('g', [
node('4'),
]),
node('h'),
]
def walk(tree, fn, parent=None):
for node in tree:
fn(node, parent)
walk(node.get('children', ()), fn, parent=node)
def get_all_nodes_and_parents(tree):
nodes = {}
parents = {}
def add_node(node, parent):
nodes[node['id']] = node
parents[node['id']] = (parent['id'] if parent else None)
walk(tree, add_node)
return (nodes, parents)
def treediff(t1, t2):
n1, p1 = get_all_nodes_and_parents(t1)
n2, p2 = get_all_nodes_and_parents(t2)
new_nodes = set(n2.keys()) - set(n1.keys())
del_nodes = set(n1.keys()) - set(n2.keys())
for node_id in sorted(new_nodes):
yield 'create node %s' % node_id
for node_id in sorted(del_nodes):
yield 'delete node %s' % node_id
for node_id in n2:
if p1.get(node_id) != p2.get(node_id):
yield 'move node %s from %s to %s' % (node_id, p1.get(node_id), p2.get(node_id))
for op in treediff(tree1, tree2):
print(op)
此输出
create node 3
create node 4
create node 6
create node d
create node e
create node g
delete node 7
delete node b
delete node f
move node 3 from None to c
move node 1 from a to d
move node * from 5 to 1
move node 5 from b to d
move node 6 from None to e
move node 4 from None to g
进一步的改进是直接在新父节点下创建新节点,但这需要增加复杂性来跟踪创建顺序,因此父母是在新子节点之前创建的。