binary-tree: Update.

pull/13/head
Jim Blandy 3 years ago
parent fd7632bb9b
commit 88dbb7c344

@ -4,14 +4,25 @@
name = "binary-tree" name = "binary-tree"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"rand 0.3.23", "rand",
] ]
[[package]] [[package]]
name = "fuchsia-cprng" name = "cfg-if"
version = "0.1.1" version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "getrandom"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]] [[package]]
name = "libc" name = "libc"
@ -20,70 +31,53 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
[[package]] [[package]]
name = "rand" name = "ppv-lite86"
version = "0.3.23" version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
dependencies = [
"libc",
"rand 0.4.6",
]
[[package]] [[package]]
name = "rand" name = "rand"
version = "0.4.6" version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
dependencies = [ dependencies = [
"fuchsia-cprng",
"libc", "libc",
"rand_core 0.3.1", "rand_chacha",
"rdrand", "rand_core",
"winapi", "rand_hc",
] ]
[[package]] [[package]]
name = "rand_core" name = "rand_chacha"
version = "0.3.1" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
dependencies = [ dependencies = [
"rand_core 0.4.2", "ppv-lite86",
"rand_core",
] ]
[[package]] [[package]]
name = "rand_core" name = "rand_core"
version = "0.4.2" version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7"
dependencies = [ dependencies = [
"rand_core 0.3.1", "getrandom",
] ]
[[package]] [[package]]
name = "winapi" name = "rand_hc"
version = "0.3.9" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
dependencies = [ dependencies = [
"winapi-i686-pc-windows-gnu", "rand_core",
"winapi-x86_64-pc-windows-gnu",
] ]
[[package]] [[package]]
name = "winapi-i686-pc-windows-gnu" name = "wasi"
version = "0.4.0" version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"

@ -2,6 +2,7 @@
name = "binary-tree" name = "binary-tree"
version = "0.1.0" version = "0.1.0"
authors = ["You <you@example.com>"] authors = ["You <you@example.com>"]
edition = "2018"
[dependencies] [dependencies]
rand = "0.3.14" rand = "0.8"

@ -1,18 +1,16 @@
#![allow(dead_code)] #![allow(dead_code)]
extern crate rand;
// An ordered collection of `T`s. // An ordered collection of `T`s.
enum BinaryTree<T> { enum BinaryTree<T> {
Empty, Empty,
NonEmpty(Box<TreeNode<T>>) NonEmpty(Box<TreeNode<T>>),
} }
// A part of a BinaryTree. // A part of a BinaryTree.
struct TreeNode<T> { struct TreeNode<T> {
element: T, element: T,
left: BinaryTree<T>, left: BinaryTree<T>,
right: BinaryTree<T> right: BinaryTree<T>,
} }
#[test] #[test]
@ -26,37 +24,42 @@ fn binary_tree_size() {
} }
#[test] #[test]
fn test_hand_building_tree_of_planets() { fn build_binary_tree() {
use self::BinaryTree::*; use self::BinaryTree::*;
let jupiter_tree = NonEmpty(Box::new(TreeNode { let jupiter_tree = NonEmpty(Box::new(TreeNode {
element: "Jupiter", element: "Jupiter",
left: Empty, left: Empty,
right: Empty right: Empty,
})); }));
let mercury_tree = NonEmpty(Box::new(TreeNode { let mercury_tree = NonEmpty(Box::new(TreeNode {
element: "Mercury", element: "Mercury",
left: Empty, left: Empty,
right: Empty right: Empty,
})); }));
let mars_tree = NonEmpty(Box::new(TreeNode { let mars_tree = NonEmpty(Box::new(TreeNode {
element: "Mars", element: "Mars",
left: jupiter_tree, left: jupiter_tree,
right: mercury_tree right: mercury_tree,
})); }));
let venus_tree = NonEmpty(Box::new(TreeNode { let venus_tree = NonEmpty(Box::new(TreeNode {
element: "Venus", element: "Venus",
left: Empty, left: Empty,
right: Empty right: Empty,
})); }));
let uranus_tree = NonEmpty(Box::new(TreeNode { let uranus_tree = NonEmpty(Box::new(TreeNode {
element: "Uranus", element: "Uranus",
left: Empty, left: Empty,
right: venus_tree right: venus_tree,
})); }));
let tree = NonEmpty(Box::new(TreeNode { let tree = NonEmpty(Box::new(TreeNode {
element: "Saturn", element: "Saturn",
left: mars_tree, left: mars_tree,
right: uranus_tree right: uranus_tree,
})); }));
assert_eq!(tree.walk(), assert_eq!(tree.walk(),
@ -80,18 +83,20 @@ impl<T: Clone> BinaryTree<T> {
impl<T: Ord> BinaryTree<T> { impl<T: Ord> BinaryTree<T> {
fn add(&mut self, value: T) { fn add(&mut self, value: T) {
match *self { match *self {
BinaryTree::Empty => BinaryTree::Empty => {
*self = BinaryTree::NonEmpty(Box::new(TreeNode { *self = BinaryTree::NonEmpty(Box::new(TreeNode {
element: value, element: value,
left: BinaryTree::Empty, left: BinaryTree::Empty,
right: BinaryTree::Empty right: BinaryTree::Empty,
})), }))
BinaryTree::NonEmpty(ref mut node) => }
BinaryTree::NonEmpty(ref mut node) => {
if value <= node.element { if value <= node.element {
node.left.add(value); node.left.add(value);
} else { } else {
node.right.add(value); node.right.add(value);
} }
}
} }
} }
} }
@ -113,18 +118,22 @@ fn test_add_method_2() {
let mut tree = BinaryTree::Empty; let mut tree = BinaryTree::Empty;
tree.add("Mercury"); tree.add("Mercury");
tree.add("Venus"); tree.add("Venus");
for planet in vec!["Mars", "Jupiter", "Saturn", "Uranus"] { for planet in vec!["Mars", "Jupiter", "Saturn", "Uranus"] {
tree.add(planet); tree.add(planet);
} }
assert_eq!(tree.walk(), assert_eq!(
vec!["Jupiter", "Mars", "Mercury", "Saturn", "Uranus", "Venus"]); tree.walk(),
vec!["Jupiter", "Mars", "Mercury", "Saturn", "Uranus", "Venus"]
);
} }
// From chapter 15: Iterators
use self::BinaryTree::*; use self::BinaryTree::*;
// The state of an in-order traversal of a `BinaryTree`. // The state of an in-order traversal of a `BinaryTree`.
struct TreeIter<'a, T: 'a> { struct TreeIter<'a, T> {
// A stack of references to tree nodes. Since we use `Vec`'s // A stack of references to tree nodes. Since we use `Vec`'s
// `push` and `pop` methods, the top of the stack is the end of the // `push` and `pop` methods, the top of the stack is the end of the
// vector. // vector.
@ -164,14 +173,13 @@ impl<'a, T> Iterator for TreeIter<'a, T> {
type Item = &'a T; type Item = &'a T;
fn next(&mut self) -> Option<&'a T> { fn next(&mut self) -> Option<&'a T> {
// Find the node this iteration must produce, // Find the node this iteration must produce,
// or finish the iteration. // or finish the iteration. (Use the `?` operator
let node = match self.unvisited.pop() { // to return immediately if it's `None`.)
None => return None, let node = self.unvisited.pop()?;
Some(n) => n
}; // After `node`, the next thing we produce must be the leftmost
// child in `node`'s right subtree, so push the path from here
// The next node after this one is the leftmost child of // down. Our helper method turns out to be just what we need.
// this node's right child, so push the path from here down.
self.push_left_edge(&node.right); self.push_left_edge(&node.right);
// Produce a reference to this node's value. // Produce a reference to this node's value.
@ -188,24 +196,40 @@ fn external_iterator() {
} }
// Build a small tree. // Build a small tree.
let subtree_l = make_node(Empty, "mecha", Empty); let mut tree = BinaryTree::Empty;
let subtree_rl = make_node(Empty, "droid", Empty); tree.add("jaeger");
let subtree_r = make_node(subtree_rl, "robot", Empty); tree.add("robot");
let tree = make_node(subtree_l, "Jaeger", subtree_r); tree.add("droid");
tree.add("mecha");
// Iterate over it. // Iterate over it.
let mut v = Vec::new(); let mut v = Vec::new();
for kind in &tree { for kind in &tree {
v.push(*kind); v.push(*kind);
} }
assert_eq!(v, ["mecha", "Jaeger", "droid", "robot"]); assert_eq!(v, ["droid", "jaeger", "mecha", "robot"]);
assert_eq!(tree.iter()
.map(|name| format!("mega-{}", name))
.collect::<Vec<_>>(),
vec!["mega-droid", "mega-jaeger",
"mega-mecha", "mega-robot"]);
let mut iterator = (&tree).into_iter();
assert_eq!(iterator.next(), Some(&"droid"));
assert_eq!(iterator.next(), Some(&"jaeger"));
assert_eq!(iterator.next(), Some(&"mecha"));
assert_eq!(iterator.next(), Some(&"robot"));
assert_eq!(iterator.next(), None);
// Construct a tree by hand.
let left_subtree = make_node(Empty, "mecha", Empty); let left_subtree = make_node(Empty, "mecha", Empty);
let right_subtree = make_node(make_node(Empty, "droid", Empty), let right_subtree = make_node(make_node(Empty, "droid", Empty),
"robot", "robot",
Empty); Empty);
let tree = make_node(left_subtree, "Jaeger", right_subtree); let tree = make_node(left_subtree, "Jaeger", right_subtree);
// Try initializing the iterator ourselves and see if it runs.
let mut v = Vec::new(); let mut v = Vec::new();
let mut iter = TreeIter { unvisited: vec![] }; let mut iter = TreeIter { unvisited: vec![] };
iter.push_left_edge(&tree); iter.push_left_edge(&tree);
@ -214,33 +238,23 @@ fn external_iterator() {
} }
assert_eq!(v, ["mecha", "Jaeger", "droid", "robot"]); assert_eq!(v, ["mecha", "Jaeger", "droid", "robot"]);
// Iterate by shared reference.
let mut v = Vec::new(); let mut v = Vec::new();
for kind in &tree { for kind in &tree {
v.push(*kind); v.push(*kind);
} }
assert_eq!(v, ["mecha", "Jaeger", "droid", "robot"]); assert_eq!(v, ["mecha", "Jaeger", "droid", "robot"]);
// Iterate, taking ownership.
let mut v = Vec::new(); let mut v = Vec::new();
let mut state = tree.into_iter(); let mut state = tree.into_iter();
while let Some(kind) = state.next() { while let Some(kind) = state.next() {
v.push(*kind); v.push(*kind);
} }
assert_eq!(v, ["mecha", "Jaeger", "droid", "robot"]); assert_eq!(v, ["mecha", "Jaeger", "droid", "robot"]);
assert_eq!(tree.iter()
.map(|name| format!("mega-{}", name))
.collect::<Vec<_>>(),
vec!["mega-mecha", "mega-Jaeger",
"mega-droid", "mega-robot"]);
let mut iterator = tree.into_iter();
assert_eq!(iterator.next(), Some(&"mecha"));
assert_eq!(iterator.next(), Some(&"Jaeger"));
assert_eq!(iterator.next(), Some(&"droid"));
assert_eq!(iterator.next(), Some(&"robot"));
assert_eq!(iterator.next(), None);
} }
#[test] #[test]
fn other_cloned() { fn other_cloned() {
use std::collections::BTreeSet; use std::collections::BTreeSet;
@ -257,13 +271,12 @@ fn other_cloned() {
#[test] #[test]
fn fuzz() { fn fuzz() {
fn make_random_tree(p: f32) -> BinaryTree<i32> { fn make_random_tree(p: f32) -> BinaryTree<i32> {
use rand::{ThreadRng, thread_rng}; use rand::prelude::*;
use rand::distributions::range::Range; use rand::thread_rng;
use rand::distributions::Sample; use rand::rngs::ThreadRng;
fn make(p: f32, next: &mut i32, rng: &mut ThreadRng) -> BinaryTree<i32> { fn make(p: f32, next: &mut i32, rng: &mut ThreadRng) -> BinaryTree<i32> {
let mut range = Range::new(0.0, 1.0); if rng.gen_range(0.0 .. 1.0) > p {
if range.sample(rng) > p {
Empty Empty
} else { } else {
let left = make(p * p, next, rng); let left = make(p * p, next, rng);

Loading…
Cancel
Save