Same fringe: Difference between revisions

m
(→‎{{header|Clojure}}: slight tweak)
m (→‎{{header|Wren}}: Minor tidy)
 
(43 intermediate revisions by 18 users not shown)
Line 11:
The package is generic, which allows Data to be essentially of any type.
 
<langsyntaxhighlight Adalang="ada">generic
type Data is private;
package Bin_Trees is
Line 36:
end record;
 
end Bin_Trees;</langsyntaxhighlight>
 
The implementation is straightforward.
 
<langsyntaxhighlight Adalang="ada">with Ada.Unchecked_Deallocation;
 
package body Bin_Trees is
Line 91:
end Tree;
 
end Bin_Trees;</langsyntaxhighlight>
 
Next, we specify and implement package that defines a task type for tree traversal. This allows us to run any number of tree traversals in parallel, even on the same tree.
 
<langsyntaxhighlight Adalang="ada"> generic
with procedure Process_Data(Item: Data);
with function Stop return Boolean;
Line 105:
-- except when Stop becomes true; in this case, the task terminates
end Inorder_Task;
end Bin_Trees.Traverse;</langsyntaxhighlight>
 
<langsyntaxhighlight Adalang="ada"> package body Bin_Trees.Traverse is
task body Inorder_Task is
procedure Inorder(Tree: Tree_Type) is
Line 129:
Finish;
end Inorder_Task;
end Bin_Trees.Traverse;</langsyntaxhighlight>
 
When comparing two trees T1 and T2, we will define two tasks, a "Producer.Inorder_Task" and a "Consumer.Inorder_Task". The producer will write data items to a buffer, the consumer will read items from the buffer and compare them with its own data items. Both tasks will terminate when the consumer finds a data item different from the one written by the producer, or when either task has written its last item and the other one has items left.
Line 135:
A third auxiliary task just waits until the consumer has finished and the result of the fringe comparison can be read.
 
<langsyntaxhighlight Adalang="ada">with Ada.Text_IO, Bin_Trees.Traverse;
 
procedure Main is
Line 296:
Ada.Text_IO.New_Line;
end loop;
end Main;</langsyntaxhighlight>
 
Note that we do not call Destroy_Tree to reclaim the dynamic memory. In our case, this is not needed since the memory will be reclaimed at the end of Main, anyway.
Line 313:
DIFF( 4, 1 ); DIFF( 4, 2 ); same( 4, 3 ); same( 4, 4 ); DIFF( 4, 5 );
DIFF( 5, 1 ); DIFF( 5, 2 ); DIFF( 5, 3 ); DIFF( 5, 4 ); same( 5, 5 ); </pre>
 
=={{header|Bracmat}}==
<langsyntaxhighlight Bracmatlang="bracmat">( ( T
=
. ( next
Line 351 ⟶ 352:
, (((a.b).c).x.y.z)
)
);</langsyntaxhighlight>
Output:
<pre>x,x
Line 370 ⟶ 371:
, (((a.b).c).x.y.z)
equal</pre>
 
=={{header|C}}==
With rudimentary coroutine support based on ucontext. I don't know if it will compile on anything other than GCC.
<langsyntaxhighlight lang="c">#include <stdio.h>
#include <stdlib.h>
#include <ucontext.h>
Line 492 ⟶ 494:
 
return 0;
}</langsyntaxhighlight>
 
=={{header|c sharp|C#}}==
This task is almost custom designed for C# LINQ and is really trivial using that. Most of the following is support code. The only two routines that actually implement the task at hand are CompareTo and GetLeaves at the bottom. GetLeaves is a really simple BinTree procedure to retreive the leaves from left to right into an IEnumerable. That IEnumerable can be zipped with the result of GetLeaves on another tree and the results compared giving us our final answer and since everything is deferred in LINQ, this has the desirable property spoken of in the problem's description that no comparisons are done after a non-matching pair.
<syntaxhighlight lang="csharp">
using System;
using System.Collections.Generic;
using System.Linq;
 
namespace Same_Fringe
{
class Program
{
static void Main()
{
var rnd = new Random(110456);
var randList = Enumerable.Range(0, 20).Select(i => rnd.Next(1000)).ToList();
var bt1 = new BinTree<int>(randList);
// Shuffling will create a tree with the same values but different topology
Shuffle(randList, 428);
var bt2 = new BinTree<int>(randList);
Console.WriteLine(bt1.CompareTo(bt2) ? "True compare worked" : "True compare failed");
// Insert a 0 in the first tree which should cause a failure
bt1.Insert(0);
Console.WriteLine(bt1.CompareTo(bt2) ? "False compare failed" : "False compare worked");
}
 
static void Shuffle<T>(List<T> values, int seed)
{
var rnd = new Random(seed);
 
for (var i = 0; i < values.Count - 2; i++)
{
var iSwap = rnd.Next(values.Count - i) + i;
var tmp = values[iSwap];
values[iSwap] = values[i];
values[i] = tmp;
}
}
}
 
// Define other methods and classes here
class BinTree<T> where T:IComparable
{
private BinTree<T> _left;
private BinTree<T> _right;
private T _value;
 
private BinTree<T> Left
{
get { return _left; }
}
 
private BinTree<T> Right
{
get { return _right; }
}
 
// On interior nodes, any value greater than or equal to Value goes in the
// right subtree, everything else in the left.
private T Value
{
get { return _value; }
}
 
public bool IsLeaf { get { return Left == null; } }
 
private BinTree(BinTree<T> left, BinTree<T> right, T value)
{
_left = left;
_right = right;
_value = value;
}
 
public BinTree(T value) : this(null, null, value) { }
 
public BinTree(IEnumerable<T> values)
{
// ReSharper disable PossibleMultipleEnumeration
_value = values.First();
foreach (var value in values.Skip(1))
{
Insert(value);
}
// ReSharper restore PossibleMultipleEnumeration
}
 
public void Insert(T value)
{
if (IsLeaf)
{
if (value.CompareTo(Value) < 0)
{
_left = new BinTree<T>(value);
_right = new BinTree<T>(Value);
}
else
{
_left = new BinTree<T>(Value);
_right = new BinTree<T>(value);
_value = value;
}
}
else
{
if (value.CompareTo(Value) < 0)
{
Left.Insert(value);
}
else
{
Right.Insert(value);
}
}
}
 
public IEnumerable<T> GetLeaves()
{
if (IsLeaf)
{
yield return Value;
yield break;
}
foreach (var val in Left.GetLeaves())
{
yield return val;
}
foreach (var val in Right.GetLeaves())
{
yield return val;
}
}
 
internal bool CompareTo(BinTree<T> other)
{
return other.GetLeaves().Zip(GetLeaves(), (t1, t2) => t1.CompareTo(t2) == 0).All(f => f);
}
}
}
</syntaxhighlight>
 
Example output:
<pre>
True Compare worked
False Compare worked
</pre>
 
=={{header|C++}}==
Walk through the trees using C++20 coroutines.
<syntaxhighlight lang="cpp">#include <algorithm>
#include <coroutine>
#include <iostream>
#include <memory>
#include <tuple>
#include <variant>
 
using namespace std;
 
class BinaryTree
{
// C++ does not have a built in tree type. The binary tree is a recursive
// data type that is represented by an empty tree or a node the has a value
// and a left and right sub-tree. A tuple represents the node and unique_ptr
// represents an empty vs. non-empty tree.
using Node = tuple<BinaryTree, int, BinaryTree>;
unique_ptr<Node> m_tree;
 
public:
// Provide ways to make trees
BinaryTree() = default; // Make an empty tree
BinaryTree(BinaryTree&& leftChild, int value, BinaryTree&& rightChild)
: m_tree {make_unique<Node>(move(leftChild), value, move(rightChild))} {}
BinaryTree(int value) : BinaryTree(BinaryTree{}, value, BinaryTree{}){}
BinaryTree(BinaryTree&& leftChild, int value)
: BinaryTree(move(leftChild), value, BinaryTree{}){}
BinaryTree(int value, BinaryTree&& rightChild)
: BinaryTree(BinaryTree{}, value, move(rightChild)){}
 
// Test if the tree is empty
explicit operator bool() const
{
return (bool)m_tree;
}
 
// Get the value of the root node of the tree
int Value() const
{
return get<1>(*m_tree);
}
 
// Get the left child tree
const BinaryTree& LeftChild() const
{
return get<0>(*m_tree);
}
 
// Get the right child tree
const BinaryTree& RightChild() const
{
return get<2>(*m_tree);
}
};
 
// Define a promise type to be used for coroutines
struct TreeWalker {
struct promise_type {
int val;
 
suspend_never initial_suspend() noexcept {return {};}
suspend_never return_void() noexcept {return {};}
suspend_always final_suspend() noexcept {return {};}
void unhandled_exception() noexcept { }
 
TreeWalker get_return_object()
{
return TreeWalker{coroutine_handle<promise_type>::from_promise(*this)};
}
 
suspend_always yield_value(int x) noexcept
{
val=x;
return {};
}
};
 
coroutine_handle<promise_type> coro;
 
TreeWalker(coroutine_handle<promise_type> h): coro(h) {}
 
~TreeWalker()
{
if(coro) coro.destroy();
}
 
// Define an iterator type to work with the coroutine
class Iterator
{
const coroutine_handle<promise_type>* m_h = nullptr;
 
public:
Iterator() = default;
constexpr Iterator(const coroutine_handle<promise_type>* h) : m_h(h){}
 
Iterator& operator++()
{
m_h->resume();
return *this;
}
 
Iterator operator++(int)
{
auto old(*this);
m_h->resume();
return old;
}
 
int operator*() const
{
return m_h->promise().val;
}
 
bool operator!=(monostate) const noexcept
{
return !m_h->done();
return m_h && !m_h->done();
}
 
bool operator==(monostate) const noexcept
{
return !operator!=(monostate{});
}
};
 
constexpr Iterator begin() const noexcept
{
return Iterator(&coro);
}
 
constexpr monostate end() const noexcept
{
return monostate{};
}
};
 
// Allow the iterator to be used like a standard library iterator
namespace std {
template<>
class iterator_traits<TreeWalker::Iterator>
{
public:
using difference_type = std::ptrdiff_t;
using size_type = std::size_t;
using value_type = int;
using pointer = int*;
using reference = int&;
using iterator_category = std::input_iterator_tag;
};
}
 
// A coroutine that iterates though all of the fringe nodes
TreeWalker WalkFringe(const BinaryTree& tree)
{
if(tree)
{
auto& left = tree.LeftChild();
auto& right = tree.RightChild();
if(!left && !right)
{
// a fringe node because it has no children
co_yield tree.Value();
}
 
for(auto v : WalkFringe(left))
{
co_yield v;
}
 
for(auto v : WalkFringe(right))
{
co_yield v;
}
}
co_return;
}
 
// Print a tree
void PrintTree(const BinaryTree& tree)
{
if(tree)
{
cout << "(";
PrintTree(tree.LeftChild());
cout << tree.Value();
PrintTree(tree.RightChild());
cout <<")";
}
}
 
// Compare two trees
void Compare(const BinaryTree& tree1, const BinaryTree& tree2)
{
// Create a lazy range for both trees
auto walker1 = WalkFringe(tree1);
auto walker2 = WalkFringe(tree2);
// Compare the ranges.
bool sameFringe = ranges::equal(walker1.begin(), walker1.end(),
walker2.begin(), walker2.end());
// Print the results
PrintTree(tree1);
cout << (sameFringe ? " has same fringe as " : " has different fringe than ");
PrintTree(tree2);
cout << "\n";
}
 
int main()
{
// Create two trees that that are different but have the same fringe nodes
BinaryTree tree1(BinaryTree{6}, 77, BinaryTree{BinaryTree{3}, 77,
BinaryTree{77, BinaryTree{9}}});
BinaryTree tree2(BinaryTree{BinaryTree{BinaryTree{6}, 77}, 77, BinaryTree{
BinaryTree{3}, 77, BinaryTree{9}}});
// Create a tree with a different fringe
BinaryTree tree3(BinaryTree{BinaryTree{BinaryTree{6}, 77}, 77, BinaryTree{77, BinaryTree{9}}});
 
// Compare the trees
Compare(tree1, tree2);
Compare(tree1, tree3);
}</syntaxhighlight>
{{out}}
<pre>
((6)77((3)77(77(9)))) has same fringe as (((6)77)77((3)77(9)))
((6)77((3)77(77(9)))) has different fringe than (((6)77)77(77(9)))
</pre>
 
=={{header|Clojure}}==
Line 502 ⟶ 878:
''children'' returns the children of a branch node; ''content'' returns the content of a branch node.
A fringe value is either the content of a branch node without children, or a non-branch node.
<langsyntaxhighlight lang="clojure">(defn fringe-seq [branch? children content tree]
(letfn [(walk [node]
(lazy-seq
Line 510 ⟶ 886:
(mapcat walk (children node)))
(list node))))]
(walk tree)))</langsyntaxhighlight>
For this problem, binary trees are represented as vectors, whose nodes are either [''content'' ''left'' ''right''] or just ''content''.
<langsyntaxhighlight lang="clojure">(defn vfringe-seq [v] (fringe-seq vector? #(remove nil? (rest %)) first v))
(println (vfringe-seq [10 1 2])) ; (1 2)
(println (vfringe-seq [10 [1 nil nil] [20 2 nil]])) ; (1 2)</langsyntaxhighlight>
Then we can use a general sequence-equality function:
<langsyntaxhighlight lang="clojure">(defn seq= [s1 s2]
(cond
(and (empty? s1) (empty? s2)) true
(not= (empty? s1) (empty? s2)) false
(= (first s1) (first s2)) (recur (rest s1) (rest s2))
:else false))</langsyntaxhighlight>
 
=={{header|D}}==
===Short Version===
A short recursive solution that is not lazy (and lacks the const/immutable/pure/nothrow):
<langsyntaxhighlight lang="d">struct Node(T) {
T data;
Node* L, R;
Line 547 ⟶ 923:
auto t3 = new N(1, new N(2, new N(3, new N(40), new N(51))));
writeln(sameFringe(t1, t3));
}</langsyntaxhighlight>
{{out}}
<pre>true
Line 554 ⟶ 930:
===Strong Lazy Version===
This version is quite long because it tries to be reliable. The code contains contracts, unit tests, annotations, and so on.
<langsyntaxhighlight lang="d">import std.array: empty;
import std.algorithm: equal;
 
Line 597 ⟶ 973:
private Stack!BT stack;
 
pure nothrow invariant() {
assert(stack.empty || isLeaf(stack.head));
}
Line 605 ⟶ 981:
stack.push(t);
if (!isLeaf(t)) {
// Here the invariant() doesn't hold.
// invariant() isn't called for private methods.
nextLeaf();
}
}
Line 747 ⟶ 1,123:
writeln("sameFringe(t1, t2): ", sameFringe(t1, t2));
writeln("sameFringe(t1, t3): ", sameFringe(t1, t3));
}</langsyntaxhighlight>
{{out}}
<pre>fringe(t1): [40, 50]
Line 754 ⟶ 1,130:
sameFringe(t1, t2): true
sameFringe(t1, t3): false</pre>
 
===Range Generator Version (Lazy)===
<syntaxhighlight lang="d">import std.stdio, std.concurrency, std.range, std.algorithm;
 
struct Node(T) {
T data;
Node* L, R;
}
 
Generator!T fringe(T)(Node!T* t1) {
return new typeof(return)({
if (t1 != null) {
if (t1.L == null && t1.R == null) // Is a leaf.
yield(t1.data);
else
foreach (data; t1.L.fringe.chain(t1.R.fringe))
yield(data);
}
});
}
 
bool sameFringe(T)(Node!T* t1, Node!T* t2) {
return t1.fringe.equal(t2.fringe);
}
 
void main() {
alias N = Node!int;
 
auto t1 = new N(10, new N(20, new N(30, new N(40), new N(50))));
auto t2 = new N(1, new N(2, new N(3, new N(40), new N(50))));
sameFringe(t1, t2).writeln;
 
auto t3 = new N(1, new N(2, new N(3, new N(40), new N(51))));
sameFringe(t1, t3).writeln;
 
auto t4 = new N(1, new N(2, new N(3, new N(40))));
sameFringe(t1, t4).writeln;
 
N* t5;
sameFringe(t1, t5).writeln;
sameFringe(t5, t5).writeln;
 
auto t6 = new N(2);
auto t7 = new N(1, new N(2));
sameFringe(t6, t7).writeln;
}</syntaxhighlight>
{{out}}
<pre>true
false
false
false
true
true</pre>
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import "fmt"
Line 826 ⟶ 1,255:
&node{int: 13}}
fmt.Println(sameFringe(t1, t2)) // prints true.
}</langsyntaxhighlight>
 
=={{header|Haskell}}==
Line 832 ⟶ 1,261:
 
To get the fringe, we can simply use the solution for [[Flatten a list#Haskell|Flatten a list]], slightly modified for a binary tree instead of a general tree:
<syntaxhighlight lang ="haskell">data Tree a = Leaf a | Node (Tree a) (Tree a)
= Leaf a
deriving (Show, Eq)
| Node (Tree a)
(Tree a)
deriving (Show, Eq)
 
fringe :: Tree a -> [a]
Line 839 ⟶ 1,271:
fringe (Node n1 n2) = fringe n1 ++ fringe n2
 
sameFringe :: (Eq a) => Tree a -> Tree a -> Bool
:: (Eq a)
=> Tree a -> Tree a -> Bool
sameFringe t1 t2 = fringe t1 == fringe t2
 
main :: IO ()
main = do
let a = Node (Leaf 1) (Node (Leaf 2) (Node (Leaf 3) (Node (Leaf 4) (Leaf 5))))
b = Node (Leaf 1) (Node (Node (Leaf 2) (Leaf 3)) (Node (Leaf 4) (Leaf 5)))
c = Node (Node (Node (Node (Leaf 1) (Leaf 2)) (Leaf 3)) (Leaf 4)) (Leaf 5)
print $ sameFringex a a=
print $ sameFringe a bNode
print $ sameFringe a c (Leaf 1)
(Node
 
let x = Node (Leaf 1) (Node (Leaf 2) (Node (Leaf 3) (Node (Leaf 4) (Node (Leaf 5) (Leaf 6))))2)
y = Node (Leaf 0) (Node (Node (Leaf 23) (Node (Leaf 3)4) (Node (Leaf 45) (Leaf 56)))))
zy = Node (Leaf 10) (Node (Node (Leaf 2) (NodeLeaf 3)) (Node (Leaf 4) (Leaf 3)) (Leaf 5)))
z = Node (Leaf 1) (Node (Leaf 2) (Node (Node (Leaf 4) (Leaf 3)) (Leaf 5)))
print $ sameFringe a x
mapM_ print $ sameFringe a <$> [a, b, c, x, y, z]</syntaxhighlight>
{{Out}}
print $ sameFringe a z</lang>
{{out}}
<pre>True
True
Line 868 ⟶ 1,302:
The following solution works in both languages:
 
<langsyntaxhighlight lang="unicon">procedure main()
aTree := [1, [2, [4, [7]], [5]], [3, [6, [8], [9]]]]
bTree := [1, [2, [4, [7]], [5]], [3, [6, [8], [9]]]]
Line 897 ⟶ 1,331:
procedure preorder(L)
if \L then suspend L | preorder(L[2|3])
end</langsyntaxhighlight>
 
Output:
Line 910 ⟶ 1,344:
=={{header|J}}==
 
<langsyntaxhighlight Jlang="j">sameFringe=: -:&([: ; <S:0)</langsyntaxhighlight>
 
Note that the time/space optimizations here can change with the language implementation, but current implementations make no effort to treat trees efficiently.
Line 918 ⟶ 1,352:
Anyways, here's a recursive routine to convert a flat list into a binary tree:
 
<langsyntaxhighlight Jlang="j">list2tree=: (<.@-:@# ({. ,&<&list2tree}. ) ])^:(1<#)</langsyntaxhighlight>
 
And, here are two differently structured trees which represent the same underlying data:
 
<langsyntaxhighlight Jlang="j">bp=: list2tree p: i.11
ubp=: p:L:0] 10;~list2tree i.10</langsyntaxhighlight>
 
And, here's our original operation in action (<code>1 {:: ubp</code> is a subtree of ubp which omits a leaf node):
 
<langsyntaxhighlight Jlang="j"> ubp sameFringe bp
1
bp sameFringe 1 {:: ubp
0</langsyntaxhighlight>
 
=={{header|Java}}==
Line 937 ⟶ 1,371:
 
'''Code:'''
<langsyntaxhighlight lang="java">import java.util.*;
 
class SameFringe
Line 1,057 ⟶ 1,491:
}
}
}</langsyntaxhighlight>
 
'''Output:'''
Line 1,065 ⟶ 1,499:
areLeavesSame(1, 2)? true
areLeavesSame(2, 3)? false</pre>
 
=={{header|jq}}==
{{works with|jq|1.4}}
A binary tree can be conveniently represented in jq as a nested array, e.g. [1,[2,3]]. This is the data structure used by same_fringe(t;u) as defined in this section.
 
With this data structure, a test for whether two trees, s and t, have the same fringes could be implemented simply as:
<syntaxhighlight lang="jq">(t|flatten) == (s|flatten)</syntaxhighlight>
but this entails generating the lists of leaves.
 
To accomplish the "same fringe" task efficiently in jq 1.4 without generating a list of leaves, a special-purpose function is needed. This special-purpose function, which is here named "next", would ordinarily be defined as an inner function of "same_fringe", but for clarity, it is defined as a top-level function.
<syntaxhighlight lang="jq"># "next" allows one to generate successive leaves, one at a time. This is accomplished
# by ensuring that the non-null output of a call to "next" can also serve as input.
#
# "next" returns null if there are no more leaves, otherwise it returns [leaf, nodes]
# where "leaf" is the next leaf, and nodes is an array of nodes still to be traversed.
# Input has the same form, but on input, "leaf" is ignored unless it is an array.
def next:
def _next:
.[0] as $node | .[1] as $nodes
| if ($node|type) == "array" then
if $node|length != 2 then
error("improper node: \($node) should have 2 items") else . end
| [ $node[0], [$node[1]] + $nodes]
elif $nodes|length > 0 then [$nodes[0], $nodes[1:]]
else null
end;
_next as $n
| if $n == null then null
elif ($n[0]|type) == "array" then $n|next
else $n
end;
 
# t and u must be binary trees
def same_fringe(t;u):
# x and y must be suitable for input to "next"
def eq(x;y):
if x == null then y == null
elif y == null then false
elif x[0] != y[0] then false
else eq( x|next; y|next)
end;
 
eq([t,[]]|next; [u,[]]|next) ;</syntaxhighlight>
'''Example''':
<syntaxhighlight lang="jq"> [1,[2,[3,[4,[5,[6,7]]]]]] as $a
| [[[[[[1,2],3],4],5],6],7] as $b
| [[[1,2],3],[4,[5,[6,7]]]] as $c
| [[[1,2],2],4] as $d
| same_fringe($a;$a), same_fringe($b;$b), same_fringe($c;$c),
same_fringe($a;$b), same_fringe($a;$c), same_fringe($b;$c),
same_fringe($a;$d), same_fringe($d;$c), same_fringe($b;$d),
 
same_fringe( ["a",["b",["c",[["x","y"],"z"]]]];
[[["a","b"],"c"],["x",["y","z"]]] )</syntaxhighlight>
{{out}}
<syntaxhighlight lang="sh">$ jq -n -f Same_Fringe.jq
true
true
true
true
true
true
false
false
false
true
</syntaxhighlight>
 
=={{header|Julia}}==
<syntaxhighlight lang="julia">
using Lazy
 
"""
Input a tree for display as a fringed structure.
"""
function fringe(tree)
fringey(node::Pair) = [fringey(i) for i in node]
fringey(leaf::Int) = leaf
fringey(tree)
end
 
 
"""
equalsfringe() uses a reduction to a lazy 1D list via
getleaflist() for its "equality" of fringes
"""
getleaflist(tree::Int) = [tree]
getleaflist(tree::Pair) = vcat(getleaflist(seq(tree[1])), getleaflist(seq(tree[2])))
getleaflist(tree::Lazy.LazyList) = vcat(getleaflist(tree[1]), getleaflist(tree[2]))
getleaflist(tree::Void) = []
equalsfringe(t1, t2) = (getleaflist(t1) == getleaflist(t2))
 
 
a = 1 => 2 => 3 => 4 => 5 => 6 => 7 => 8
b = 1 => (( 2 => 3 ) => (4 => (5 => ((6 => 7) => 8))))
c = (((1 => 2) => 3) => 4) => 5 => 6 => 7 => 8
x = 1 => 2 => 3 => 4 => 5 => 6 => 7 => 8 => 9
y = 0 => 2 => 3 => 4 => 5 => 6 => 7 => 8
z = 1 => 2 => (4 => 3) => 5 => 6 => 7 => 8
 
prettyprint(s) = println(replace("$s", r"\{Any,1\}|Any|Array\{T,1\}\swhere\sT|Array|", ""))
prettyprint(fringe(a))
prettyprint(fringe(b))
prettyprint(fringe(c))
prettyprint(fringe(x))
prettyprint(fringe(y))
prettyprint(fringe(z))
 
prettyprint(getleaflist(a))
prettyprint(getleaflist(b))
prettyprint(getleaflist(c))
 
println(equalsfringe(a, a))
println(equalsfringe(a, b))
println(equalsfringe(a, c))
println(equalsfringe(b, c))
println(equalsfringe(a, x) == false)
println(equalsfringe(a, y) == false)
println(equalsfringe(a, z) == false)
</syntaxhighlight>
{{output}}
<pre>
[1, [2, [3, [4, [5, [6, [7, 8]]]]]]]
[1, [[2, 3], [4, [5, [[6, 7], 8]]]]]
[[[[1, 2], 3], 4], [5, [6, [7, 8]]]]
[1, [2, [3, [4, [5, [6, [7, [8, 9]]]]]]]]
[0, [2, [3, [4, [5, [6, [7, 8]]]]]]]
[1, [2, [[4, 3], [5, [6, [7, 8]]]]]]
[1, 2, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 8]
true
true
true
true
true
true
true
</pre>
 
=={{header|Lua}}==
 
In this example, an internal node of a tree is either a "branch", a table with exactly two elements, or the distinguished value None -- everything else is a fringe (leaf) value. <i>fringeiter</i> creates an iterator function to produce successive elements of the fringe.
 
<syntaxhighlight lang="lua">local type, insert, remove = type, table.insert, table.remove
 
None = {} -- a unique object for a truncated branch (i.e. empty subtree)
function isbranch(node) return type(node) == 'table' and #node == 2 end
function left(node) return node[1] end
function right(node) return node[2] end
 
function fringeiter(tree)
local agenda = {tree}
local function push(item) insert(agenda, item) end
local function pop() return remove(agenda) end
return function()
while #agenda > 0 do
node = pop()
if isbranch(node) then
push(right(node))
push(left(node))
elseif node == None then
-- continue
else
return node
end
end
end
end
 
function same_fringe(atree, btree)
local anext = fringeiter(atree or None)
local bnext = fringeiter(btree or None)
local pos = 0
repeat
local aitem, bitem = anext(), bnext()
pos = pos + 1
if aitem ~= bitem then
return false, string.format("at position %d, %s ~= %s", pos, aitem, bitem)
end
until not aitem
return true
end
 
t1 = {1, {2, {3, {4, {5, None}}}}}
t2 = {{1,2}, {{3, 4}, 5}}
t3 = {{{1,2}, 3}, 4}
 
function compare_fringe(label, ta, tb)
local equal, nonmatch = same_fringe(ta, tb)
io.write(label .. ": ")
if equal then
print("same fringe")
else
print(nonmatch)
end
end
 
compare_fringe("(t1, t2)", t1, t2)
compare_fringe("(t1, t3)", t1, t3)
</syntaxhighlight>
 
{{out}}
<pre>(t1, t2): equal fring
(t1, t3): at position 5, 5 ~= nil</pre>
 
=={{header|Nim}}==
We define an iterator “nodes” which yields the successive nodes of a tree. To compare the fringes, we get the successive nodes using an iterator for each tree and stop iterations as soon as a difference is found.
 
<syntaxhighlight lang="nim">import random, sequtils, strutils
 
type Node = ref object
value: int
left, right: Node
 
 
proc add(tree: var Node; value: int) =
## Add a node to a tree (or subtree), insuring values are in increasing order.
if tree.isNil:
tree = Node(value: value)
elif value <= tree.value:
tree.left.add value
else:
tree.right.add value
 
 
proc newTree(list: varargs[int]): Node =
## Create a new tree with the given nodes.
for value in list:
result.add value
 
 
proc `$`(tree: Node): string =
# Display a tree.
if tree.isNil: return
result = '(' & $tree.left & $tree.value & $tree.right & ')'
 
 
iterator nodes(tree: Node): Node =
## Yield the successive leaves of a tree.
## Iterators cannot be recursive, so we have to manage a stack.
## Note: with Nim 1.4 a bug prevents to use a closure iterator,
## so we use an inline iterator which is not optimal here.
 
type
Direction {.pure.} = enum Up, Down
Item = (Node, Direction)
 
var stack: seq[Item]
stack.add (nil, Down) # Sentinel to avoid checking for empty stack.
 
var node = tree
var dir = Down
 
while not node.isNil:
if dir == Down and not node.left.isNil:
# Process left subtree.
stack.add (node, Up)
node = node.left
else:
yield node
# Process right subtree of pop an element form stack.
(node, dir) = if node.right.isNil: stack.pop() else: (node.right, Down)
 
 
proc haveSameFringe(tree1, tree2: Node): bool =
## Return true if the trees have the same fringe.
## Check is done node by node and terminates as soon as
## a difference is encountered.
let iter1 = iterator: Node = (for node in tree1.nodes: yield node)
let iter2 = iterator: Node = (for node in tree2.nodes: yield node)
while true:
let node1 = iter1()
let node2 = iter2()
if iter1.finished and iter2.finished: return true # Both terminates at same round.
if iter1.finished or iter2.finished: return false # One terminates before the other.
if node1.value != node2.value: return false
 
 
when isMainModule:
randomize()
var values = [1, 2, 3, 4, 5, 6, 7, 8, 9]
 
values.shuffle()
let tree1 = newTree(values)
echo "First tree: ", tree1
 
values.shuffle()
let tree2 = newTree(values)
echo "Second tree: ", tree2
 
let s = if haveSameFringe(tree1, tree2): "have " else: "don’t have "
echo "The trees ", s, "same fringe: ", toSeq(tree1.nodes()).mapIt(it.value).join(", ")</syntaxhighlight>
 
{{out}}
<pre>First tree: (1((2(3))4(((5(6))7)8(9))))
Second tree: (((((1)2((3)4))5)6(7(8)))9)
The trees have same fringe: 1, 2, 3, 4, 5, 6, 7, 8, 9</pre>
 
=={{header|OCaml}}==
While we could use a lazy datatype such as [http://caml.inria.fr/pub/docs/manual-ocaml/libref/Stream.html Stream] for this problem, this example implements the short-circuit behavoirbehavior (returning on first mismatch) by tracking the parse state.
<langsyntaxhighlight OCamllang="ocaml">type 'a btree = Leaf of 'a | BTree of ('a btree * 'a btree)
 
let rec next = function
Line 1,090 ⟶ 1,823:
let check a b =
print_endline (if samefringe a b then "same" else "different") in
check u v; check v u; check v w;</langsyntaxhighlight>
Output:
<pre>same
Line 1,101 ⟶ 1,834:
The tree iterator is pretty simple: we use array references with index 0 as the left subtree and index 1 holding the right subtree. So as we go down the tree towards the first leaf, we push each right subtree that we will consider later onto the rtree stack. Eventually, we'll hit a leaf and return it. The next time we go into the iterator, we simply pull off the last deferred subtree and continue the process.
 
<langsyntaxhighlight lang="perl">
#!/usr/bin/perl
use strict;
Line 1,139 ⟶ 1,872:
}
}
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 1,146 ⟶ 1,879:
tree[2] vs tree[3]: Different</pre>
 
=={{header|Perl 6Phix}}==
<!--<syntaxhighlight lang="phix">(notonline)-->
{{Works with|Rakudo|#67 ("Bicycle")}}
<span style="color: #000080;font-style:italic;">--
Unlike in Perl 5, where <tt>=></tt> is just a synonym for comma, in Perl 6 it creates a true Pair object. So here we use Pair objects for our "cons" cells, just as if we were doing this in Lisp. We use the <tt>gather/take</tt> construct to harvest the leaves lazily as the elements are visited with a standard recursive algorithm, using multiple dispatch to differentiate nodes from leaves. The <tt>eqv</tt> value equivalence is applied to the two lists in parallel.
-- demo\rosetta\Same_Fringe.exw
<lang perl6>sub fringe ($tree) {
-- ============================
multi sub fringey (Pair $node) { fringey $_ for $node.kv; }
--
multi sub fringey ( Any $leaf) { take $leaf; }
-- In some cases it may help to replace the single res with a table, such
-- that if you have concurrent task pairs {1,2} and {3,4} with a table of
-- result indexes ridx = {1,1,2,2}, then each updates res[ridx[tidx]]. In
-- other words if extending tasks[] rather than overwriting it, you would
-- also extend res[] and ridx[] and sdata[], and need freelist handling.
--</span>
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- (multitasking)</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">tests</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">}</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">tasks</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">sdata</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">active_tasks</span>
<span style="color: #004080;">bool</span> <span style="color: #000000;">show_details</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">scan</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">tree</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">level</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">tidx</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">object</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">left</span><span style="color: #0000FF;">,</span><span style="color: #000000;">data</span><span style="color: #0000FF;">,</span><span style="color: #000000;">right</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">tree</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">res</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">left</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #000000;">scan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">left</span><span style="color: #0000FF;">,</span><span style="color: #000000;">level</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">tidx</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">sdata</span><span style="color: #0000FF;">[</span><span style="color: #000000;">tidx</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">data</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">show_details</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"task[%d] sets sdata[%d] to %v\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">tidx</span><span style="color: #0000FF;">,</span><span style="color: #000000;">tidx</span><span style="color: #0000FF;">,</span><span style="color: #000000;">data</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">res</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">task_suspend</span><span style="color: #0000FF;">(</span><span style="color: #000000;">task_self</span><span style="color: #0000FF;">())</span>
<span style="color: #000000;">task_yield</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">right</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #000000;">scan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">right</span><span style="color: #0000FF;">,</span><span style="color: #000000;">level</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">tidx</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">level</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">show_details</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"task[%d] ends\n"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">tidx</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">active_tasks</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">1</span>
<span style="color: #000000;">tasks</span><span style="color: #0000FF;">[</span><span style="color: #000000;">tidx</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #000000;">sdata</span><span style="color: #0000FF;">[</span><span style="color: #000000;">tidx</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #000080;font-style:italic;">-- (or use a separate flag or tasks[tidx])</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">t1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">t2</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">tasks</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">task_create</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">routine_id</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"scan"</span><span style="color: #0000FF;">),{</span><span style="color: #000000;">tests</span><span style="color: #0000FF;">[</span><span style="color: #000000;">t1</span><span style="color: #0000FF;">],</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">}),</span>
<span style="color: #000000;">task_create</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">routine_id</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"scan"</span><span style="color: #0000FF;">),{</span><span style="color: #000000;">tests</span><span style="color: #0000FF;">[</span><span style="color: #000000;">t2</span><span style="color: #0000FF;">],</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">})}</span>
<span style="color: #000000;">active_tasks</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">2</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">active_tasks</span><span style="color: #0000FF;">></span><span style="color: #000000;">0</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">2</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">tasks</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">task_schedule</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tasks</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">task_yield</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">res</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000080;font-style:italic;">-- (nb next might only be valid for active_tasks==2)</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">compare</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sdata</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],</span><span style="color: #000000;">sdata</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">])</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">show_details</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"compare(%v,%v) ==&gt; %d, active tasks:%d\n"</span><span style="color: #0000FF;">,</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">sdata</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],</span><span style="color: #000000;">sdata</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">],</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">active_tasks</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"test(%d,%d):%d\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">t1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">t2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">res</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #0000FF;">?</span><span style="color: #008000;">"started"</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">l</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">3</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">r</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">3</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #000000;">l</span><span style="color: #0000FF;">,</span><span style="color: #000000;">r</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">show_details</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #0000FF;">?</span><span style="color: #008000;">"done"</span>
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">wait_key</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
"started"
task[1] sets sdata[1] to 1
task[2] sets sdata[2] to 1
compare(1,1) ==> 0, active tasks:2
task[1] sets sdata[1] to 2
task[2] sets sdata[2] to 2
compare(2,2) ==> 0, active tasks:2
task[1] ends
task[2] ends
compare(-1,-1) ==> 0, active tasks:0
test(1,1):0
test(1,2):0
test(1,3):-1
test(2,1):0
test(2,2):0
test(2,3):-1
test(3,1):1
test(3,2):1
test(3,3):0
"done"
</pre>
 
=={{header|Phixmonti}}==
gather fringey $tree;
<syntaxhighlight lang="Phixmonti">include ..\Utilitys.pmt
}
 
(
sub samefringe ($a, $b) { fringe($a) eqv fringe($b) }</lang>
/# 1..3 are same #/
Testing:
<lang perl6>my $a = 1( =>"d" 2( =>"c" 3( => 4 => 5 => 6"a" =>"b" 7) =>) 8;)
my $b = 1 =>( (( 2"d" => 3"c" ) => (4 =>"a" (5"b" => ((6 => 7) => 8))));
my $c = ( ( (1 =>"d" "c" 2) =>"a" 3) =>"b" 4) => 5 => 6 => 7 => 8;
/# and this one"s different! #/
( ( ( ( ( ( "a" ) "b" ) "c" ) "d" ) "e" ) "f" )
)
 
dup
my $x = 1 => 2 => 3 => 4 => 5 => 6 => 7 => 8 => 9;
my $y = 0 => 2 => 3 => 4 => 5 => 6 => 7 => 8;
my $z = 1 => 2 => (4 => 3) => 5 => 6 => 7 => 8;
 
len for >ps
say so samefringe $a, $a;
tps get flatten ps> set
say so samefringe $a, $b;
endfor
say so samefringe $a, $c;
 
len 1 - for >ps
say not samefringe $a, $x;
tps get swap tps 1 + get rot ==
say not samefringe $a, $y;
( "Tree " tps " and " ps> 1 + " is " ) lprint
say not samefringe $a, $z;</lang>
if "the same." else "different." endif ?
endfor</syntaxhighlight>
{{out}}
<pre>Tree 1 and 2 is the same.
<pre>True
Tree 2 and 3 is the same.
True
Tree 3 and 4 is different.
True
 
True
=== Press any key to exit ===</pre>
True
True</pre>
 
=={{header|PicoLisp}}==
This uses coroutines to traverse the trees, so it works only in the 64-bit version.
<langsyntaxhighlight PicoLisplang="picolisp">(de nextLeaf (Rt Tree)
(co Rt
(recur (Tree)
Line 1,201 ⟶ 2,037:
(NIL (= Node1 Node2)) ) )
(co "rt1")
(co "rt2") ) )</langsyntaxhighlight>
Test:
<langsyntaxhighlight PicoLisplang="picolisp">: (balance '*Tree1 (range 1 7))
-> NIL
: (for N (5 4 6 3 7 1 2) (idx '*Tree2 N T))
Line 1,229 ⟶ 2,065:
 
: (cmpTrees *Tree1 *Tree2)
-> T</langsyntaxhighlight>
 
=={{header|Python}}==
This solution visits lazily the two trees in lock step like in the Perl 6Raku example, and stops at the first miss-match.
<langsyntaxhighlight lang="python">try:
from itertools import zip_longest as izip_longest # Python 3.x
except:
Line 1,267 ⟶ 2,103:
assert not same_fringe(a, x)
assert not same_fringe(a, y)
assert not same_fringe(a, z)</langsyntaxhighlight>
{{out}}
There is no output, which signifies success.
Line 1,273 ⟶ 2,109:
=={{header|Racket}}==
 
=== Lazy Language ===
The following is a slight modification of the <tt>same-fringe?</tt> program from Dorai Sitaram's 1993 PLDI paper titled "Handling Control". This solution uses the <tt>fcontrol</tt> delimited continuation operator.
 
The same fringe problem is one of the classic cases where a lazy
<lang racket>
language solution is extremely simple: just flatten the two trees and
compare the resulting lists. Racket has a lazy language implementation,
but instead of using it for the whole code, the following program has
just the tree comparison part defined in the lazy language, and it gets
used outside, using the plain default Racket language --- in the test
submodule. To verify this code, put it in some file, and run it with
“<tt>raco test <i>the-file.rkt</i></tt>. The same exact test module can
be added to any of the following variations, it's omitted for brevity.
 
<syntaxhighlight lang="racket">
#lang racket
 
(require racket/control)
(module same-fringe lazy
(defineprovide (makesame-fringe-getter tree?)
(define (same-fringe? t1 t2)
(λ ()
(! (equal? (flatten t1) (flatten t2))))
(define (flatten tree)
(if (list? tree)
(apply append (map flatten tree))
(list tree))))
 
(require 'same-fringe)
 
(module+ test
(require rackunit)
(check-true (same-fringe? '((1 2 3) ((4 5 6) (7 8)))
'(((1 2 3) (4 5 6)) (7 8))))
(check-false (same-fringe? '((1 2 3) ((4 5 6) (7 8)))
'(((1 2 3) (4 6)) (8)))))
</syntaxhighlight>
 
{{out}}
<pre>raco test: (submod "/some/file.rkt" test)
2 tests passed</pre>
 
 
=== Channels and Threads ===
 
This version flattens the trees into channels, and then compares the
contents of the two channels. Each call to <tt>fringe->channel</tt>
creates a channel for the element stream, then fires up a (green) thread
that feeds it.
 
<syntaxhighlight lang="racket">
#lang racket
 
(define (fringe->channel tree)
(define ch (make-channel))
(thread (λ() (let loop ([tree tree])
(if (list? tree) (for-each loop tree) (channel-put ch tree)))
(channel-put ch (void)))) ; mark the end
ch)
 
(define (same-fringe? tree1 tree2)
(define ch1 (fringe->channel tree1))
(define ch2 (fringe->channel tree2))
(let loop ()
(let ([x1 (channel-get ch1)] [x2 (channel-get ch2)])
(and (equal? x1 x2) (or (void? x1) (loop))))))
</syntaxhighlight>
 
Channels are just a one of several thread-communication devices which
could have been used, including a simple unix-like pipe-based solution.
Note the limit on the amount of allowed buffering: it can be any
(finite) value, since there are three independent threads that are
running.
 
<syntaxhighlight lang="racket">
#lang racket
 
(define (pipe-fringe tree)
(define-values [I O] (make-pipe 100))
(thread (λ() (let loop ([tree tree])
(if (list? tree) (for-each loop tree) (fprintf O "~s\n" tree)))
(close-output-port O)))
I)
 
(define (same-fringe? tree1 tree2)
(define i1 (pipe-fringe tree1))
(define i2 (pipe-fringe tree2))
(let loop ()
(let ([x1 (read i1)] [x2 (read i2)])
(and (equal? x1 x2) (or (eof-object? x1) (loop))))))
</syntaxhighlight>
 
=== Generators ===
 
This version is very similar, except that now we use generators:
 
<syntaxhighlight lang="racket">
#lang racket
(require racket/generator)
 
(define (fringe-generator tree)
(generator ()
(let loop ([tree tree])
(if (list? tree) (for-each loop tree) (yield tree)))))
(match tree
 
[(cons a d) (loop a)
(loop d)]
['() (void)]
[else (fcontrol tree)]))
(fcontrol 'done)))
(define (same-fringe? tree1 tree2)
(letdefine loopg1 ([get-fringe1 (make-fringe-gettergenerator tree1)])
(define [get-fringe2g2 (make-fringe-gettergenerator tree2)])
(let loop (% (get-fringe1)
(let (λ[x1 (fringe1g1)] get-fringe1[x2 (g2)])
(and (equal? x1 x2) (%or (void? x1) (get-fringe2loop))))))
</syntaxhighlight>
(λ (fringe2 get-fringe2)
 
(and (equal? fringe1 fringe2)
 
(or (eq? fringe1 'done)
=== Continuations ===
(loop get-fringe1 get-fringe2)))))))))
 
Finally, this is a more low-level solution, using continuation conreol
;; unit tests
operators. The following is a slight modification of the
(require rackunit)
(check-true (<tt>same-fringe?</tt> '((1program 2from 3)Dorai ((4 5Sitaram's 6)1993 (7PLDI 8)))paper
titled "Handling Control". This solution uses the <tt>fcontrol</tt>
'(((1 2 3) (4 5 6)) (7 8))))
delimited continuation operator.
(check-false (same-fringe? '((1 2 3) ((4 5 6) (7 8)))
 
'(((1 2 3) (4 6)) (8))))
<syntaxhighlight lang="racket">
</lang>
#lang racket
 
(require racket/control)
 
(define (fringe-iterator tree)
(λ() (let loop ([tree tree])
(if (list? tree) (for-each loop tree) (fcontrol tree)))
(fcontrol (void))))
 
(define (same-fringe? tree1 tree2)
(let loop ([iter1 (fringe-iterator tree1)]
[iter2 (fringe-iterator tree2)])
(% (iter1)
(λ (x1 iter1)
(% (iter2)
(λ (x2 iter2)
(and (equal? x1 x2)
(or (void? x1) (loop iter1 iter2)))))))))
</syntaxhighlight>
 
=={{header|Raku}}==
(formerly Perl 6)
{{works with|Rakudo|2018.03}}
Unlike in Perl 5, where <tt>=></tt> is just a synonym for comma, in Raku it creates a true Pair object. So here we use Pair objects for our "cons" cells, just as if we were doing this in Lisp. We use the <tt>gather/take</tt> construct to harvest the leaves lazily as the elements are visited with a standard recursive algorithm, using multiple dispatch to differentiate nodes from leaves. The <tt>eqv</tt> value equivalence is applied to the two lists in parallel.
<syntaxhighlight lang="raku" line>sub fringe ($tree) {
multi sub fringey (Pair $node) { fringey $_ for $node.kv; }
multi sub fringey ( Any $leaf) { take $leaf; }
 
gather fringey $tree;
}
 
sub samefringe ($a, $b) { fringe($a) eqv fringe($b) }
 
# Testing:
 
my $a = 1 => 2 => 3 => 4 => 5 => 6 => 7 => 8;
my $b = 1 => (( 2 => 3 ) => (4 => (5 => ((6 => 7) => 8))));
my $c = (((1 => 2) => 3) => 4) => 5 => 6 => 7 => 8;
 
my $x = 1 => 2 => 3 => 4 => 5 => 6 => 7 => 8 => 9;
my $y = 0 => 2 => 3 => 4 => 5 => 6 => 7 => 8;
my $z = 1 => 2 => (4 => 3) => 5 => 6 => 7 => 8;
 
say so samefringe $a, $a;
say so samefringe $a, $b;
say so samefringe $a, $c;
 
say not samefringe $a, $x;
say not samefringe $a, $y;
say not samefringe $a, $z;</syntaxhighlight>
{{out}}
<pre>True
True
True
True
True
True</pre>
 
=={{header|REXX}}==
Line 1,312 ⟶ 2,290:
===Version 1 using father node ===
 
<langsyntaxhighlight REXXlang="rexx">/* REXX ***************************************************************
* Same Fringe
* 1 A A
Line 1,487 ⟶ 2,465:
i=mknode('I',t); Call attrite i,f,t
End
Return</langsyntaxhighlight>
Output:
<pre>
Line 1,501 ⟶ 2,479:
 
===Version 2 without using father node ===
<langsyntaxhighlight lang="rexx">/* REXX ***************************************************************
* Same Fringe
= 1 A A
Line 1,639 ⟶ 2,617:
i=mknode('I',t); Call attrite i,f,t
End
Return</langsyntaxhighlight>
Output is the same as for Version 1
 
===version 1.1===
This REXX example is a re-writtenre─written program that mimics the first version (above).
<br><br>It has:
* elided a subroutine
* elided superfluous DO-END groups
* elided some stemmed array tails
* elided some REXX variables (lvl, debug, ...)
* simplified some stem names
* displays the tree (ASCII display)
* changed tree names so as to not conflict with leaf names
* uses non-case sensative tree names
* used boolean based variables as logicals
* expanded messages
* a streamlined make_tree subroutine
<lang rexx>/*REXX pgm examines leaves of two binary trees. Tree used is as above.*/
_=left('',28); say _ ' A A '
say _ ' / \ ◄────1st tree / \ '
say _ ' / \ / \ '
say _ ' / \ / \ '
say _ ' B C B C '
say _ ' / \ / 2nd tree────► / \ / '
say _ ' D E F D E F '
say _ ' / / \ / / \ '
say _ 'G H I G δ I '
say; #=0 /*#: # of leaves. */
parse var # done. 1 node. /*set all these variables to zero*/
call make_tree '1st'
call make_tree '2nd'
z1=root.1st; L1=node.1st.z1; done.1st.z1=1 /*L1 is a leaf on 1st tree*/
z2=z1; L2=node.2nd.z2; done.2nd.z2=1 /*L2 " " " " 2nd " */
 
This REXX version has:
do #%2 /*loop for the number of leaves. */
:::* &nbsp; elided a subroutine
if L1==L2 then do
:::* &nbsp; elided superfluous &nbsp; '''do ── end''' &nbsp; groups
if L1==0 then call sayX 'The trees are equal.'
:::* &nbsp; elided some stemmed array tails
say ' The ' L1 " leaf is identical in both trees."
:::* &nbsp; elided an unneeded '''select''' structure
do until \done.1st.z1
:::* &nbsp; simplified some stem names
z1=go_next(z1,'1st'); L1=node.1st.z1
:::* &nbsp; displays the tree &nbsp; (as an ASCII display)
end
:::* &nbsp; changed ''TREE'' names so as to not conflict with ''LEAF'' names
done.1st.z1=1
:::* &nbsp; uses non─case sensitive tree names
do until \done.2nd.z2
:::* &nbsp; used boolean based variables as ''logicals''
z2=go_next(z2,'2nd'); L2=node.2nd.z2
:::* &nbsp; expanded message texts
end
:::* &nbsp; combined subroutines &nbsp; '''ATTLEFT''' &nbsp; and &nbsp; '''ATTRIGHT''' &nbsp; into one
done.2nd.z2=1
:::* &nbsp; streamlined the &nbsp; '''MAKE_TREE''' &nbsp; subroutine
end
<syntaxhighlight lang="rexx">/*REXX pgm examines the leaves of 2 binary trees (as shown below), and finds inequities.*/
else select
_= left('', 28); say _ " when L1==0A then call sayX L2 'exceeds leaves in 1st tree' A "
when L2==0 then callsay sayX_ L1 'exceeds leaves" in 2nd / \ ◄════1st tree' / \ "
otherwise say _ call" sayX 'A difference is: ' L1/ '¬=' L2 \ / \ "
end say _ " /*select* \ / \ "
say _ " B C B C "
end /*#%2*/
say _ " / \ / 2nd tree════► / \ / "
exit
say _ " D E F D E F "
/*──────────────────────────────────GO_NEXT subroutine──────────────────*/
say _ " / / \ / / \ "
go_next: procedure expose node.; arg q,t /*find next node.*/
say _ "G H I G δ I " ; say
next=0
if#= node0; done.t.q= 0; @._Lson\== 0 then /*isinitialize: there a# left(leaves), branch inDONE., tree?nodes*/
do t#=1 for 2; call make_tree t#; end /*define tree numbers 1 and 2. */
if node.t.q._Lson.done==0 then do /*has this node been visited yet?*/
z1= root.1; L1= @.1.z1; done.1.z1= 1 /*L1: is a leaf on tree number next=node1.t.q._Lson /*──► next node. */
z2= z1; L2= @.2.z2; done.2.z2= 1 /*L2: " " " node.t.q._Lson.done=1 /*mark" Lson done " " 2. */
do #%2 end /*loop for the number of (tree) leaves.*/
if L1==L2 then do; if L1==0 then do; say 'The trees are equal.'; leave; end
if next==0 then
say 'The ' L1 " leaf is identical in both trees."
if node.t.q._Rson\==0 then /*is there a right tree branch ? */
do until \done.1.z1; z1=nxt(z1,1); L1=@.1.z1; end; done.1.z1=1
if node.t.q._Rson.done==0 then do /*has this node been visited yet?*/
do until \done.2.z2; z2=nxt(z2,2); nextL2=node@.t2.q._Rsonz2; end; /*──► next node*/done.2.z2=1
node.t.q._Rson.done=1 /*mark Rson don*/iterate
end
if L1==0 then say L2 'exceeds leaves in 1st tree'
if next==0 then next=node.t.q._dad /*process the father node. */
if L2==0 then say L1 'exceeds leaves in 2nd tree'
return next /*the next node (or 0, if done).*/
say 'A difference is: ' L1 "¬=" L2; leave
/*──────────────────────────────────MAKE_NODE subroutine────────────────*/
end /*#%2*/
make_node: parse arg name,t; # = #+1 /*make a new node/branch on tree.*/
exit 0
q = node.t.0 + 1; node.t.q = name; node.t.q._dad = 0
/*──────────────────────────────────────────────────────────────────────────────────────*/
node.t.q._Lson = 0; node.t.q._Rson = 0; node.t.0 = q
return q nxt: procedure expose @.; arg q,t; next= . /*numberfind of thenext node justin tree. created*/
if @.t.q._Lson\==0 & @.t.q._Lson.vis==0 then /*L branch & not visited ? */
/*──────────────────────────────────MAKE_TREE subroutine────────────────*/
do; next=@.t.q._Lson; @.t.q._Lson.vis=1; end /* ──►next node; Lside done*/
make_tree: procedure expose node. root. #; arg tree /*build a tree.*/
if next==. & @.t.q._Rson\==0 & hhh@.t.q._Rson.vis=='δ' 0 then /*theR oddbranch duck& innot thevisited whole? tree.*/
do; next=@.t.q._Rson; @.t.q._Rson.vis=1; end /* ──►next node; Rside done*/
if tree=='1ST' then hhh='H'
if next==. then next= @.t.q._dad; return next /*father a=make_node('A',tree)node; zero if root.tree=adone*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
b=make_node('B',tree); call sonL b,a,tree
make_node: parse arg name,t; #= # + 1; q= @.t.0 + 1 /*make new node/branch on tree*/
c=make_node('C',tree); call sonR c,a,tree
@.t.q= name; @.t.q._Lson= 0; d@.t.0=make_node('D',tree); call sonL d,b,treeq
@.t.q._dad= 0; @.t.q._Rson= 0; return q /*number of node just e=make_node('E',tree); call sonR e,b,treecreated.*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
f=make_node('F',tree); call sonL f,c,tree
make_tree: procedure expose @. root. #; parse arg tree /*construct a couple of trees.*/
g=make_node('G',tree); call sonL g,d,tree
a= make_node('A', tree); /*quack?*/ h=make_node(hhh,root.tree)= a; call sonL h,f hhh= substr('Hδ', tree, 1)
b= i=make_node('IB', tree); call sonRson i'L',f b, a, tree
c= make_node('C', tree); call son 'R', c, a, tree
return
d= make_node('D', tree); call son 'L', d, b, tree
/*──────────────────────────────────SAYX subroutine─────────────────────*/
sayX: say; say arg(1); say; e= make_node('E', tree); exit call son /*tell'R', msge, &b, exit.*/tree
f= make_node('F', tree); call son 'L', f, c, tree
/*──────────────────────────────────SONL subroutine─────────────────────*/
g= make_node('G', tree); call son 'L', g, d, tree
sonL: procedure expose node.; parse arg son,dad,t /*build left son. */
h= make_node(hhh, tree); call node.t.son._dad=dad; 'L', h, f, tree q=node.t.dad._Lson/*quacks like a duck? */
i= make_node('I', tree); call son 'R', i, f, tree; return
if q\==0 then do; node.t.q._dad=son; node.t.son._Lson=q; end
/*──────────────────────────────────────────────────────────────────────────────────────*/
node.t.dad._Lson=son
son: procedure expose @.; parse arg ?,son,dad,t; LR= '_'?"SON"; @.t.son._dad= dad
return
q= @.t.dad.LR; if q\==0 then do; @.t.q._dad= son; @.t.son.LR= q; end
/*──────────────────────────────────SONR subroutine─────────────────────*/
@.t.dad.LR= son; return</syntaxhighlight>
sonR: procedure expose node.; parse arg son,dad,t /*build right son.*/
{{out|output}}
node.t.son._dad=dad; q=node.t.dad._Rson
<pre>
if q\==0 then do; node.t.q._dad=son; node.t.son._Rson=q; end
A A
node.t.dad._Rson=son
/ \ ◄════1st tree / \
if node.t.dad._Lson>0 then node.t.le._brother=node.t.dad._Rson
/ \ / \
return</lang>
/ \ / \
'''output'''
B C B C
<pre style="overflow:scroll">
/ \ A / 2nd tree════► / \ A/
D E / \F ◄────1st tree / \ D E F
/ / / \ / / / \
G / H \I G / \δ I
B C B C
/ \ / 2nd tree────► / \ /
D E F D E F
/ / \ / / \
G H I G δ I
 
The A leaf is identical in both trees.
The B leaf is identical in both trees.
The D leaf is identical in both trees.
The G leaf is identical in both trees.
The E leaf is identical in both trees.
The C leaf is identical in both trees.
The F leaf is identical in both trees.
 
The A leaf is identical in both trees.
The B leaf is identical in both trees.
The D leaf is identical in both trees.
The G leaf is identical in both trees.
The E leaf is identical in both trees.
The C leaf is identical in both trees.
The F leaf is identical in both trees.
A difference is: H ¬= δ
</pre>
 
=={{header|Scheme}}==
 
Descend provides a list, or stack, of the leftmost ''unvisited'' nodes at each level of the tree. Two such lists are used as cursors to keep track of the remaining nodes. The main loop compares the top of each list (ie the leftmost remaining node) and breaks with ''false'' if different, or calls Ascend to update the lists. Updating may require calling Descend again if more unvisited left-nodes are found. If the end of both lists is reached simultaneously, and therefore the end of both trees, ''true'' is returned.
 
<syntaxhighlight lang="scheme">; binary tree helpers from "Structure and Interpretation of Computer Programs" 2.3.3
(define (entry tree) (car tree))
(define (left-branch tree) (cadr tree))
(define (right-branch tree) (caddr tree))
(define (make-tree entry left right)
(list entry left right))
 
; returns a list of leftmost nodes from each level of the tree
(define (descend tree ls)
(if (null? (left-branch tree))
(cons tree ls)
(descend (left-branch tree) (cons tree ls))))
 
; updates the list to contain leftmost nodes from each remaining level
(define (ascend ls)
(cond
((and (null? (cdr ls)) (null? (right-branch (car ls)))) '())
((null? (right-branch (car ls))) (cdr ls))
(else
(let ((ls (cons (right-branch (car ls))
(cdr ls))))
(if (null? (left-branch (car ls)))
ls
(descend (left-branch (car ls)) ls))))))
 
; loops thru each list until the end (true) or nodes are unequal (false)
(define (same-fringe? t1 t2)
(let next ((l1 (descend t1 '()))
(l2 (descend t2 '())))
(cond
((and (null? l1) (null? l2)) #t)
((or (null? l1)
(null? l2)
(not (eq? (entry (car l1)) (entry (car l2))))) #f)
(else (next (ascend l1) (ascend l2))))))</syntaxhighlight>
 
{{out}}
<pre>> (same-fringe? (list 1 '() (list 2 '() (list 3 '() '()))) (list 3 (list 2 (list 1 '() '()) '()) '()))
#t</pre>
 
=={{header|Sidef}}==
{{trans|Perl}}
<syntaxhighlight lang="ruby">var trees = [
# 0..2 are same
[ 'd', [ 'c', [ 'a', 'b', ], ], ],
[ [ 'd', 'c' ], [ 'a', 'b' ] ],
[ [ [ 'd', 'c', ], 'a', ], 'b', ],
# and this one's different!
[ [ [ [ [ [ 'a' ], 'b' ], 'c', ], 'd', ], 'e', ], 'f' ],
]
 
func get_tree_iterator(*rtrees) {
var tree
func {
tree = rtrees.pop
while (defined(tree) && tree.kind_of(Array)) {
rtrees.append(tree[1])
tree = tree[0]
}
return tree
}
}
 
func cmp_fringe(a, b) {
var ti1 = get_tree_iterator(a)
var ti2 = get_tree_iterator(b)
loop {
var (L, R) = (ti1(), ti2())
defined(L) && defined(R) && (L == R) && next
 !defined(L) && !defined(R) && return "Same"
return "Different"
}
}
 
for idx in ^(trees.end) {
say ("tree[#{idx}] vs tree[#{idx+1}]: ",
cmp_fringe(trees[idx], trees[idx+1]))
}</syntaxhighlight>
 
{{out}}
<pre>
tree[0] vs tree[1]: Same
tree[1] vs tree[2]: Same
tree[2] vs tree[3]: Different
</pre>
 
Line 1,769 ⟶ 2,803:
{{works with|Tcl|8.6}}
{{tcllib|struct::tree}}
<langsyntaxhighlight lang="tcl">package require Tcl 8.6
package require struct::tree
 
Line 1,801 ⟶ 2,835:
rename $c2 {}
}
}</langsyntaxhighlight>
Demonstrating:
<langsyntaxhighlight lang="tcl"># Make some trees to compare...
struct::tree t1 deserialize {
root {} {}
Line 1,822 ⟶ 2,856:
 
# Print the boolean result of doing the comparison
puts [samefringe t1 t2]</langsyntaxhighlight>
{{out}}
<pre>
c != cc
0
</pre>
 
=={{header|Wren}}==
{{trans|Go}}
{{libheader|Wren-dynamic}}
<syntaxhighlight lang="wren">import "./dynamic" for Struct
 
var Node = Struct.create("Node", ["key", "left", "right"])
 
// 'leaves' returns a fiber that yields the leaves of the tree
// until all leaves have been received.
var leaves = Fn.new { |t|
// recursive function to walk tree
var f
f = Fn.new { |n|
if (!n) return
// leaves are identified by having no children
if (!n.left && !n.right) {
Fiber.yield(n.key)
} else {
f.call(n.left)
f.call(n.right)
}
}
// return a fiber which walks the tree
return Fiber.new { f.call(t) }
}
 
var sameFringe = Fn.new { |t1, t2|
var f1 = leaves.call(t1)
var f2 = leaves.call(t2)
var l1
while (l1 = f1.call()) {
// both trees must yield a leaf, and the leaves must be equal
var l2
if ((l2 = f2.call()) && (!l2 || l1 != l2)) return false
}
// there must be nothing left in f2 after consuming all of f1
return !f2.call()
}
 
// the different shapes of the trees is shown with indention,
// the leaves being easy to spot by the key
var t1 = Node.new(3,
Node.new(1,
Node.new(1, null, null),
Node.new(2, null, null)
),
Node.new(8,
Node.new(5, null, null),
Node.new(13, null, null)
)
)
// t2 with negative values for internal nodes that can't possibly match
// positive values in t1, just to show that only leaves are being compared.
var t2 = Node.new(-8,
Node.new(-3,
Node.new(-1,
Node.new(1, null, null),
Node.new(2, null, null)
),
Node.new(5, null,null)
),
Node.new(13, null, null)
)
// t3 as t2 but with a different leave
var t3 = Node.new(-8,
Node.new(-3,
Node.new(-1,
Node.new(1, null, null),
Node.new(2, null, null)
),
Node.new(5, null,null)
),
Node.new(14, null, null) // 14 instead of 13
)
System.print("tree 1 and tree 2 have the same leaves: %(sameFringe.call(t1, t2))")
System.print("tree 1 and tree 3 have the same leaves: %(sameFringe.call(t1, t3))")
System.print("tree 2 and tree 3 have the same leaves: %(sameFringe.call(t2, t3))")</syntaxhighlight>
 
{{out}}
<pre>
tree 1 and tree 2 have the same leaves: true
tree 1 and tree 3 have the same leaves: false
tree 2 and tree 3 have the same leaves: false
</pre>
 
=={{header|zkl}}==
{{trans|Icon and Unicon}}
<syntaxhighlight lang="zkl">var G=Utils.Generator;
//Tree: (node,left,right) or (leaf) or (node,left) ...
aTree := T(1, T(2, T(4, T(7)), T(5)), T(3, T(6, T(8), T(9))));
bTree := aTree;
println("aTree and bTree ",sameFringe(aTree,bTree) and "have" or "don't have",
" the same leaves.");
cTree := T(1, T(2, T(4, T(7)), T(5)), T(3, T(6, T(8))));
dTree := T(1, T(2, T(4, T(7)), T(5)), T(3, T(6, T(8), T(9))));
println("cTree and dTree ",sameFringe(cTree,dTree) and "have"or"don't have",
" the same leaves.");
 
fcn sameFringe(a,b){ same(G(genLeaves,a),G(genLeaves,b)) }
fcn same(g1,g2){ //(Generator,Generator)
foreach n1,n2 in (g1.zip(g2)){ //-->(int,int) ...
if(n1 != n2) return(); // == return(Void)
}
return(not (g2._next() or g2._next())); //-->False if g1 or g2 has leaves
}
fcn genLeaves(tree){
switch(tree.len()){ // (), (leaf), (node,left, [right])
case(1){ vm.yield(tree[0]) } // leaf: int
case(2){ genLeaves(tree[1]); }
else { genLeaves(tree[1]); genLeaves(tree[2]); }
}
}</syntaxhighlight>
{{out}}
<pre>
aTree and bTree have the same leaves.
cTree and dTree don't have the same leaves.
</pre>
9,476

edits