एक और विकल्प, एक आलसी प्रतिस्थापन करने के आधार पर आधारित। यदि यह प्रदर्शन महत्वपूर्ण है और इसमें बहुत सारे बदलाव आएंगे, तो मैं इसका बेंचमार्किंग करने का सुझाव दूंगा।
मैंने इसे एफ # में लागू किया है, हालांकि मुझे नहीं लगता कि मैंने अपने प्रिंटिंग फ़ंक्शन को छोड़कर कुछ भी "इन्फॉर" का उपयोग किया है।
यह टेक्स्ट की एक दीवार है, मूल सिद्धांत पेड़ को आलसी रखने के लिए है, नोड को प्रतिस्थापित करने वाले फ़ंक्शन को प्रतिस्थापित करके नोड्स को प्रतिस्थापित करें।
चाल आपको किसी नोड की पहचान करने के लिए कुछ तरीका चाहिए, यह उसका स्वयं का संदर्भ/नाम नहीं है, और यह मूल्य से नहीं है। पहचान ReplacementNodes इस मामले में मैं System.Object के इस्तेमाल किया है पर duplicable होने के लिए के रूप में वे referentially प्रत्येक विशिष्ट हैं।
type TreeNode<'a> = {
getChildren: unit -> seq<TreeNode<'a>>;
value: 'a;
originalRefId: System.Object; //This is set when the onject is created,
// so we can identify any nodes that are effectivly this one
}
let BasicTreeNode : 'a ->seq<TreeNode<'a>>-> TreeNode<'a> = fun nodeValue -> fun children ->
{value = nodeValue; originalRefId = System.Object(); getChildren = fun() -> children;}
let rec ReplacementNode : TreeNode<'a> -> TreeNode<'a> -> TreeNode<'a> -> TreeNode<'a> =
fun nodeToReplace -> fun newNode -> fun baseNode ->
if (System.Object.ReferenceEquals(baseNode.originalRefId, nodeToReplace.originalRefId)) then
//If it has the same Oringal
newNode //replace the node
else
//Just another pass on node, tranform its children, keep orignial reference
{value = baseNode.value;
originalRefId = baseNode.originalRefId;
getChildren = fun() ->
baseNode.getChildren() |> Seq.map(ReplacementNode nodeToReplace newNode); }
type TreeType<'a> = {
Print: unit -> unit;
ReplaceNode: TreeNode<'a> -> TreeNode<'a> -> TreeType<'a>;
//Put all the other tree methods, like Traversals, searches etc in this type
}
let rec Tree = fun rootNode ->
{
Print = fun() ->
let rec printNode = fun node -> fun depth ->
printf "%s %A\n" (String.replicate depth " - ") node.value
for n in node.getChildren() do printNode n (depth + 1)
printNode rootNode 0
;
ReplaceNode = fun oldNode -> fun newNode ->
Tree (ReplacementNode oldNode newNode rootNode)
}
टेस्ट केस/उदाहरण:
let e = BasicTreeNode "E" Seq.empty
let d = BasicTreeNode "D" Seq.empty
let c = BasicTreeNode "C" Seq.empty
let b = BasicTreeNode "B" [d;e]
let a = BasicTreeNode "A" [b;c]
let originalTree = Tree a
printf "The Original Tree:\n"
originalTree.Print()
let g = BasicTreeNode "G" Seq.empty
let newE = BasicTreeNode "E" [g]
let newTree = originalTree.ReplaceNode e newE
printf "\n\nThe Tree with a Local Change: \n"
newTree.Print()
printf "\n\nThe Original Tree is Unchanged: \n"
originalTree.Print()
printf "\n\nThe Tree with a Second Local Change: \n"
let h = BasicTreeNode "H" Seq.empty
let newC = BasicTreeNode "C" [h]
let newTree2 = newTree.ReplaceNode c newC
newTree2.Print()
printf "\n\nTrying to Change a node that has been replaced doesn't work \n"
let i = BasicTreeNode "i" Seq.empty
let newnewC = BasicTreeNode "C" [h; i]
let newTree3 = newTree.ReplaceNode c newC //newTree.ReplaceNode newc newnewC would work
newTree3.Print()
हम परीक्षण के अंत में देखा कि का उपयोग कर वस्तु के लिए एक पुराने नोड नाम (/ संदर्भ) प्रतिस्थापित किया जा रहा काम नहीं करता। एक और नोड के संदर्भ आईडी है कि एक नए प्रकार बनाने का विकल्प है:
//Like a basicTreeNode, but reuses an existing ID, so they can be replaced for oneanother
let EdittedTreeNode = fun orignalNode -> fun nodeValue -> fun children ->
{value = nodeValue; originalRefId = orignalNode.originalRefId; getChildren = fun() -> children;}
तुम भी, ReplacementNode
परिभाषा को संपादित कर सकता है इतना है कि यह आईडी को बरकरार रखता है, नोड यह बदलता है की।
यहाँ (बस
newNode
वापस नहीं, बजाय अभी तक एक और नए नोडvalue
, औरnewNode
कीgetChildren
है, लेकिनnodetoReplace
कीoriginalRefId
वापस लौट कर) उन लोगों के लिए एक लिंक, मेरी तरह, जो पता नहीं है क्या एक "जिपर" इस संदर्भ में है: http://tomasp.net/blog/tree-zipper-query.aspx –