Skip to content

Commit

Permalink
1. [feature] breadth-first search for Node, Forest and Tree.
Browse files Browse the repository at this point in the history
  • Loading branch information
oooutlk committed Sep 7, 2018
1 parent e519fab commit 55cae43
Show file tree
Hide file tree
Showing 11 changed files with 446 additions and 21 deletions.
104 changes: 104 additions & 0 deletions src/bfs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/// breadth first search

use rust::*;

/// An enum for one visit in breadth first search.
#[derive(Debug,PartialEq,Eq)]
pub enum Visit<T> {
Data( T ), // T can be referenced, mutable referenced, or owned data
SiblingsEnd, // marks the end of consuming all the children of some node
GenerationEnd, // marks the end of consuming all the nodes of the same height in the tree
}

/// For treelike collections to split its children from its top-level data
pub trait Split<T,Item,Iter>
where Iter: Iterator<Item=Item>
{
fn split( self ) -> ( Option<T>, Option<Iter> );
}

// Queue elemnt composed of tree root and its children
struct Splitted<T,Iter> {
data: Option<T>, // None for consumed or absense( e.g. Forest has no top-level data )
iter: Option<Iter>, // None for leaf tree node
}

impl<T,Item,Iter> Splitted<T,Iter>
where Iter: Iterator<Item=Item>
{
fn from<Collection>( collection: Collection ) -> Self
where Collection: Split<T,Item,Iter>
{
let ( data, iter ) = collection.split();
Self{ data, iter }
}
}

/// An iterator in breadth-first manner
pub struct BfsIter<T,Iter> {
queue : Vec<Splitted<T,Iter>>,
en : usize, // index of queue for producing more T
gen : usize, // index of queue for generation separation
de : usize, // index of queue for consuming next T
}

impl<T,Item,Iter> BfsIter<T,Iter>
where Iter: Iterator<Item=Item>
{
/// Creates a `BfsIter` from a treelike collection.
pub fn from<Collection>( collection: Collection, de: usize ) -> Self
where Collection: Split<T,Item,Iter>
{
let queue = vec![ Splitted::from( collection )];
Self{ queue, en: 0, gen: de, de }
}

fn next_data( &mut self ) -> Option<Visit<T>> {
let data = self.queue[ self.de ].data.take().unwrap();
self.de += 1;
Some( Visit::Data( data ))
}
}

impl<T,Item,Iter> Iterator for BfsIter<T,Iter>
where Item: Split<T,Item,Iter>, Iter: Iterator<Item=Item>
{
type Item = Visit<T>;

#[inline] fn next( &mut self ) -> Option<Self::Item> {
if self.de < self.queue.len() {
self.next_data()
} else if self.gen == self.en {
if self.gen < self.queue.len() {
self.gen = self.queue.len();
Some( Visit::GenerationEnd )
} else {
None
}
} else if self.en < self.queue.len() {
let tree = if let Some( ref mut iter ) = self.queue[ self.en ].iter {
Some( iter.next() )
} else {
None
};
tree.map( |tree| { // test if any child
tree.map( |tree| { // test if all children consumed
self.queue.push( Splitted::from( tree ));
self.next_data()
}).unwrap_or_else( || { // all children consumed
self.en += 1;
if self.gen == self.en && self.gen < self.queue.len() {
self.next() // remove SiblingsEnd if followed by GenerationEnd
} else {
Some( Visit::SiblingsEnd )
}
})
}).unwrap_or_else( || { // no children
self.en += 1;
self.next()
})
} else {
None
}
}
}
23 changes: 14 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@
//!
//! do whatever you want to.
//!
//! ### Traversal
//! ### Traversal in depth-first manner
//!
//! Using `TreeWalk`/`ForestWalk` to traverse on `Tree`/`Forest`, you can:
//!
Expand All @@ -191,6 +191,12 @@
//!
//! 3. `linked::fully::Node` will track count of children nodes, and count of all descendant nodes and itself, while `linked::singly::node` does not track any size information.
//!
//! ### Traversal in breadth-first manner
//!
//! 1. `Node` provides (mutably) borrowed iterator `fn bfs_iter( &self )`/`fn bfs_iter_mut( &mut self )`.
//!
//! 2. `Tree`/`Forest` provides owned iterator `fn bfs_into_iter( self )`.
//!
//! ### Panics
//!
//! No panics unless `Clone` is involved:
Expand Down Expand Up @@ -219,33 +225,32 @@ mod rust {
#[cfg(not(feature="no_std"))] extern crate core;
#[cfg(not(feature="no_std"))] pub(crate) use std::borrow::{Borrow,BorrowMut};
#[cfg(not(feature="no_std"))] pub(crate) use std::boxed::Box;
#[cfg(not(feature="no_std"))] pub(crate) use std::cmp::Ordering;
#[cfg(not(feature="no_std"))] pub(crate) use std::cmp::Ordering::*;
#[cfg(not(feature="no_std"))] pub(crate) use std::cmp::Ordering::{self,*};
#[cfg(not(feature="no_std"))] pub(crate) use std::fmt;
#[cfg(not(feature="no_std"))] pub(crate) use std::fmt::{Debug,Display,Formatter};
#[cfg(not(feature="no_std"))] pub(crate) use std::hash::{Hasher,Hash};
#[cfg(not(feature="no_std"))] pub(crate) use std::iter::{Iterator,FromIterator,IntoIterator,FusedIterator};
#[cfg(not(feature="no_std"))] pub(crate) use std::marker::{PhantomData};
#[cfg(not(feature="no_std"))] pub(crate) use std::marker::PhantomData;
#[cfg(not(feature="no_std"))] pub(crate) use std::ops::{Deref,DerefMut,Div,Neg,Sub};
#[cfg(not(feature="no_std"))] pub(crate) use std::ptr::{null,null_mut};
#[cfg(not(feature="no_std"))] pub(crate) use std::ptr::{self,null,null_mut};
#[cfg(not(feature="no_std"))] pub(crate) use std::vec::Vec;

#[cfg(feature="no_std")] extern crate alloc;
#[cfg(feature="no_std")] pub(crate) use self::alloc::borrow::{Borrow,BorrowMut,ToOwned};
#[cfg(feature="no_std")] pub(crate) use self::alloc::boxed::Box;
#[cfg(feature="no_std")] pub(crate) use self::alloc::vec::Vec;
#[cfg(feature="no_std")] pub(crate) use core::cmp::Ordering;
#[cfg(feature="no_std")] pub(crate) use core::cmp::Ordering::*;
#[cfg(feature="no_std")] pub(crate) use core::cmp::Ordering::{self,*};
#[cfg(feature="no_std")] pub(crate) use core::fmt;
#[cfg(feature="no_std")] pub(crate) use core::fmt::{Debug,Display,Formatter};
#[cfg(feature="no_std")] pub(crate) use core::hash::{Hasher,Hash};
#[cfg(feature="no_std")] pub(crate) use core::iter::{Iterator,FromIterator,IntoIterator,FusedIterator};
#[cfg(feature="no_std")] pub(crate) use core::marker::{PhantomData};
#[cfg(feature="no_std")] pub(crate) use core::marker::PhantomData;
#[cfg(feature="no_std")] pub(crate) use core::ops::{Deref,DerefMut,Div,Neg,Sub};
#[cfg(feature="no_std")] pub(crate) use core::ptr::{null,null_mut};
#[cfg(feature="no_std")] pub(crate) use core::ptr::{self,null,null_mut};
}

pub mod linked;
pub use linked::{tr,fr,Tree,Forest,Node,Iter,IterMut,Subnode,OntoIter,Visit,TreeWalk,ForestWalk};

//pub mod potted;
pub mod bfs;
40 changes: 38 additions & 2 deletions src/linked/fully/forest.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! `Forest` composed of disjoint `Tree`s.

use super::{Node,Link,Tree,Iter,IterMut,OntoIter,Size};
use super::bfs;
use rust::*;

/// A nullable forest
Expand Down Expand Up @@ -290,7 +291,7 @@ impl<T> Forest<T> {
}
}

/// Provides a forward iterator over `Forest`'s `Tree`s' root `Node`s
/// Provides a forward iterator over child `Node`s
///
/// # Examples
///
Expand All @@ -315,7 +316,7 @@ impl<T> Forest<T> {
}}
}

/// Provides a forward iterator over `Forest`'s `Tree`s' root `Node`s with mutable references.
/// Provides a forward iterator over child `Node`s with mutable references.
///
/// # Examples
///
Expand Down Expand Up @@ -359,6 +360,41 @@ impl<T> Forest<T> {
}
}
}

/// Provides a forward iterator with owned data in a breadth-first manner
///
/// # Examples
///
/// ```
/// use trees::bfs;
/// use trees::linked::fully::tr;
///
/// let forest = -( tr(1)/tr(2)/tr(3) ) -( tr(4)/tr(5)/tr(6) );
/// let visits = forest.bfs_into_iter().collect::<Vec<_>>();
/// assert_eq!( visits, vec![
/// bfs::Visit::Data(1),
/// bfs::Visit::Data(4),
/// bfs::Visit::GenerationEnd,
/// bfs::Visit::Data(2),
/// bfs::Visit::Data(3),
/// bfs::Visit::SiblingsEnd,
/// bfs::Visit::Data(5),
/// bfs::Visit::Data(6),
/// bfs::Visit::GenerationEnd,
/// ]);
/// ```
pub fn bfs_into_iter( self ) -> bfs::BfsIter<T,IntoIter<T>> { bfs::BfsIter::from( self, 1 )}
}

impl<T> bfs::Split<T,Tree<T>,IntoIter<T>> for Forest<T> {
fn split( self ) -> ( Option<T>, Option<IntoIter<T>> ) {
let iter = if self.is_empty() {
None
} else {
Some( self.into_iter() )
};
( None, iter )
}
}

impl<T:Clone> Clone for Forest<T> {
Expand Down
2 changes: 2 additions & 0 deletions src/linked/fully/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ pub mod heap;
pub mod walk;
pub use self::walk::{Visit,TreeWalk,ForestWalk};

use super::bfs;

#[derive(Copy,Clone)]
pub struct Size {
degree : u32, // count of children node
Expand Down
83 changes: 79 additions & 4 deletions src/linked/fully/node.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Tree node implementation.

use super::{Tree,Forest,Iter,IterMut,OntoIter,Size};
use super::bfs;
use rust::*;

pub struct Link {
Expand Down Expand Up @@ -115,7 +116,7 @@ impl<T> Node<T> {
/// # Examples
///
/// ```
/// use trees::linked::singly::tr;
/// use trees::linked::fully::tr;
/// let mut tree = tr(0) /tr(1)/tr(2);
/// assert_eq!( tree.forest().to_string(), "( 1 2 )" );
/// ```
Expand All @@ -128,7 +129,7 @@ impl<T> Node<T> {
/// # Examples
///
/// ```
/// use trees::linked::singly::tr;
/// use trees::linked::fully::tr;
/// let mut tree = tr(0) /tr(1)/tr(2);
/// for child in tree.forest_mut().iter_mut() { child.data *= 10; }
/// assert_eq!( tree.to_string(), "0( 10 20 )" );
Expand Down Expand Up @@ -348,7 +349,7 @@ impl<T> Node<T> {
}
}

/// Provides a forward iterator over sub `Node`s
/// Provides a forward iterator over child `Node`s
///
/// # Examples
///
Expand All @@ -373,7 +374,7 @@ impl<T> Node<T> {
}}
}

/// Provides a forward iterator over sub `Node`s with mutable references.
/// Provides a forward iterator over child `Node`s with mutable references.
///
/// # Examples
///
Expand Down Expand Up @@ -417,6 +418,80 @@ impl<T> Node<T> {
}
}
}

/// Provides a forward iterator in a breadth-first manner
///
/// # Examples
///
/// ```
/// use trees::bfs;
/// use trees::linked::fully::tr;
///
/// let tree = tr(0) /( tr(1)/tr(2)/tr(3) ) /( tr(4)/tr(5)/tr(6) );
/// let visits = tree.root().bfs_iter().collect::<Vec<_>>();
/// assert_eq!( visits, vec![
/// bfs::Visit::Data(&0),
/// bfs::Visit::GenerationEnd,
/// bfs::Visit::Data(&1),
/// bfs::Visit::Data(&4),
/// bfs::Visit::GenerationEnd,
/// bfs::Visit::Data(&2),
/// bfs::Visit::Data(&3),
/// bfs::Visit::SiblingsEnd,
/// bfs::Visit::Data(&5),
/// bfs::Visit::Data(&6),
/// bfs::Visit::GenerationEnd,
/// ]);
/// ```
pub fn bfs_iter( &self ) -> bfs::BfsIter<&T,Iter<T>> { bfs::BfsIter::from( self, 0 )}

/// Provides a forward iterator with mutable references in a breadth-first manner
///
/// # Examples
///
/// ```
/// use trees::bfs;
/// use trees::linked::fully::tr;
///
/// let mut tree = tr(0) /( tr(1)/tr(2)/tr(3) ) /( tr(4)/tr(5)/tr(6) );
/// let visits = tree.root_mut().bfs_iter_mut().collect::<Vec<_>>();
/// assert_eq!( visits, vec![
/// bfs::Visit::Data(&mut 0),
/// bfs::Visit::GenerationEnd,
/// bfs::Visit::Data(&mut 1),
/// bfs::Visit::Data(&mut 4),
/// bfs::Visit::GenerationEnd,
/// bfs::Visit::Data(&mut 2),
/// bfs::Visit::Data(&mut 3),
/// bfs::Visit::SiblingsEnd,
/// bfs::Visit::Data(&mut 5),
/// bfs::Visit::Data(&mut 6),
/// bfs::Visit::GenerationEnd,
/// ]);
/// ```
pub fn bfs_iter_mut( &mut self ) -> bfs::BfsIter<&mut T,IterMut<T>> { bfs::BfsIter::from( self, 0 )}
}

impl<'a, T:'a> bfs::Split<&'a T,&'a Node<T>,Iter<'a,T>> for &'a Node<T> {
fn split( self ) -> ( Option<&'a T>, Option<Iter<'a,T>> ) {
let iter = if self.is_leaf() {
None
} else {
Some( self.iter() )
};
( Some( &self.data ), iter )
}
}

impl<'a, T:'a> bfs::Split<&'a mut T,&'a mut Node<T>,IterMut<'a,T>> for &'a mut Node<T> {
fn split( self ) -> ( Option<&'a mut T>, Option<IterMut<'a,T>> ) {
let iter = if self.is_leaf() {
None
} else {
Some( self.iter_mut() )
};
( Some( &mut self.data ), iter )
}
}

impl<T:Clone> ToOwned for Node<T> {
Expand Down
Loading

0 comments on commit 55cae43

Please sign in to comment.