Skip to content

Commit

Permalink
Added a ternary search tree.
Browse files Browse the repository at this point in the history
  • Loading branch information
SuprDewd committed Jul 9, 2011
1 parent 656840a commit 27fa308
Show file tree
Hide file tree
Showing 6 changed files with 495 additions and 3 deletions.
231 changes: 231 additions & 0 deletions SharpBag/Collections/TernarySearchTree.cs
@@ -0,0 +1,231 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;

namespace SharpBag.Collections
{
/// <summary>
/// A ternary search tree.
/// </summary>
/// <typeparam name="T">The type of items in the tree.</typeparam>
public class TernarySearchTree<T> : IEnumerable<T[]> where T : IComparable<T>
{
private class Node
{
public T Value { get; private set; }

public bool IsEnd { get; set; }

public Node Below { get; set; }

public Node Left { get; set; }

public Node Right { get; set; }

public Node(T value)
{
this.Value = value;
this.IsEnd = false;
}

public Node GetNextFor(T value)
{
return this.GetNextFor(this.Value.CompareTo(value));
}

public Node GetNextFor(int cmp)
{
if (cmp == 0) return this.Below;
if (cmp > 0) return this.Left;
return this.Right;
}

public void Add(Node node)
{
this.Add(node, this.Value.CompareTo(node.Value));
}

public void Add(Node node, int cmp)
{
if (cmp == 0) this.Below = node;
else if (cmp > 0) this.Left = node;
else this.Right = node;
}
}

/// <summary>
/// Gets the item count.
/// </summary>
public int Count { get; private set; }

/// <summary>
/// Gets the items.
/// </summary>
public IEnumerable<T[]> Items
{
get
{
foreach (var item in this.StartingWith(new T[0], this.Root))
{
yield return item;
}
}
}

private Node Root { get; set; }

/// <summary>
/// Initializes a new instance of the <see cref="TernarySearchTree&lt;T&gt;"/> class.
/// </summary>
public TernarySearchTree() { Count = 0; }

/// <summary>
/// Adds the specified sequence.
/// </summary>
/// <param name="sequence">The sequence.</param>
/// <returns>Whether the sequence was new.</returns>
public virtual bool Add(T[] sequence)
{
Contract.Requires(sequence.Length > 0);
bool isNew = false;

if (this.Root == null)
{
this.Root = new Node(sequence[0]);
isNew = true;
}

Node cur = this.Root;
for (int i = 0; i < sequence.Length; i++)
{
int cmp = cur.Value.CompareTo(sequence[i]);

if (cmp == 0)
{
if (i < sequence.Length - 1)
{
if (cur.Below == null)
{
cur.Below = new Node(sequence[i + 1]);
isNew = true;
}

cur = cur.Below;
}
}
else if (cmp > 0)
{
if (cur.Left == null)
{
cur.Left = new Node(sequence[i]);
isNew = true;
}

cur = cur.Left;
i--;
}
else
{
if (cur.Right == null)
{
cur.Right = new Node(sequence[i]);
isNew = true;
}

cur = cur.Right;
i--;
}

if (i + 1 == sequence.Length)
{
if (!cur.IsEnd) isNew = true;
cur.IsEnd = true;
}
}

if (isNew) this.Count++;
return isNew;
}

/// <summary>
/// Determines whether the current instance contains the specified sequence.
/// </summary>
/// <param name="sequence">The sequence.</param>
/// <returns>
/// <c>true</c> if the current instance contains the specified sequence; otherwise, <c>false</c>.
/// </returns>
public virtual bool Contains(T[] sequence)
{
Contract.Requires(sequence.Length > 0);
if (this.Root == null) return false;

Node cur = this.Root;
for (int i = 0; i < sequence.Length; i++)
{
int cmp = cur.Value.CompareTo(sequence[i]);
if (i == sequence.Length - 1 && cmp == 0) return cur.IsEnd;
cur = cur.GetNextFor(cmp);
if (cmp != 0) i--;
if (cur == null) return false;
}

return false;
}

/// <summary>
/// Gets all the sequences starting with the specified elements.
/// </summary>
/// <param name="sequence">The sequence of starting elements.</param>
/// <returns>The sequences starting with the specified elements.</returns>
public virtual IEnumerable<T[]> StartingWith(T[] sequence)
{
Contract.Requires(sequence.Length > 0);
if (this.Root == null) yield break;

Node cur = this.Root;
for (int i = 0; i < sequence.Length; i++)
{
int cmp = cur.Value.CompareTo(sequence[i]);
if (i == sequence.Length - 1 && cmp == 0) break;
cur = cur.GetNextFor(cmp);
if (cmp != 0) i--;
if (cur == null) yield break;
}

if (cur.IsEnd) yield return sequence;
if (cur.Below != null) foreach (T[] seq in this.StartingWith(sequence, cur.Below)) yield return seq;
}

private IEnumerable<T[]> StartingWith(T[] sequence, Node cur)
{
T[] seq = new T[sequence.Length + 1];
Array.Copy(sequence, seq, sequence.Length);
seq[sequence.Length] = cur.Value;

if (cur.IsEnd) yield return seq;
if (cur.Left != null) foreach (T[] s in this.StartingWith(sequence, cur.Left)) yield return s;
if (cur.Below != null) foreach (T[] s in this.StartingWith(seq, cur.Below)) yield return s;
if (cur.Right != null) foreach (T[] s in this.StartingWith(sequence, cur.Right)) yield return s;
}

/// <summary>
/// Gets the enumerator.
/// </summary>
/// <returns>The enumerator.</returns>
public IEnumerator<T[]> GetEnumerator()
{
foreach (var item in this.Items)
{
yield return item;
}
}

IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
}
133 changes: 133 additions & 0 deletions SharpBag/Collections/TernaryStringSearchTree.cs
@@ -0,0 +1,133 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SharpBag.Collections
{
/// <summary>
/// A ternary string-search tree.
/// </summary>
public class TernaryStringSearchTree : TernarySearchTree<char>, IEnumerable<string>
{
/// <summary>
/// Gets a value indicating whether the search tree is case sensitive.
/// </summary>
/// <value>
/// Whether the search tree is case sensitive.
/// </value>
public bool CaseSensitive { get; private set; }

/// <summary>
/// Gets the items.
/// </summary>
public new IEnumerable<string> Items
{
get
{
foreach (var item in base.Items)
{
yield return new String(item);
}
}
}

/// <summary>
/// Initializes a new instance of the <see cref="TernaryStringSearchTree"/> class.
/// </summary>
/// <param name="caseSensitive">Whether the search tree is case sensitive.</param>
public TernaryStringSearchTree(bool caseSensitive = true)
{
this.CaseSensitive = caseSensitive;
}

private char[] ToUpper(char[] sequence)
{
char[] upperSequence = new char[sequence.Length];
for (int i = 0; i < sequence.Length; i++) upperSequence[i] = Char.ToUpper(sequence[i]);
return upperSequence;
}

/// <summary>
/// Adds the specified sequence.
/// </summary>
/// <param name="sequence">The sequence.</param>
/// <returns>Whether the sequence was new.</returns>
public bool Add(string sequence)
{
return base.Add(this.CaseSensitive ? sequence.ToCharArray() : this.ToUpper(sequence.ToCharArray()));
}

/// <summary>
/// Adds the specified sequence.
/// </summary>
/// <param name="sequence">The sequence.</param>
/// <returns>Whether the sequence was new.</returns>
public override bool Add(char[] sequence)
{
return base.Add(this.CaseSensitive ? sequence : this.ToUpper(sequence));
}

/// <summary>
/// Determines whether the current instance contains the specified sequence.
/// </summary>
/// <param name="sequence">The sequence.</param>
/// <returns>
/// <c>true</c> if the current instance contains the specified sequence; otherwise, <c>false</c>.
/// </returns>
public bool Contains(string sequence)
{
return base.Contains(this.CaseSensitive ? sequence.ToCharArray() : this.ToUpper(sequence.ToCharArray()));
}

/// <summary>
/// Determines whether the current instance contains the specified sequence.
/// </summary>
/// <param name="sequence">The sequence.</param>
/// <returns>
/// <c>true</c> if the current instance contains the specified sequence; otherwise, <c>false</c>.
/// </returns>
public override bool Contains(char[] sequence)
{
return base.Contains(this.CaseSensitive ? sequence : this.ToUpper(sequence));
}

/// <summary>
/// Gets all the sequences starting with the specified sequence.
/// </summary>
/// <param name="sequence">The sequence of starting elements.</param>
/// <returns>The sequences starting with the specified sequence.</returns>
public IEnumerable<string> StartingWith(string sequence)
{
return base.StartingWith(this.CaseSensitive ? sequence.ToCharArray() : this.ToUpper(sequence.ToCharArray())).Select(i => new String(i));
}

/// <summary>
/// Gets all the sequences starting with the specified sequence.
/// </summary>
/// <param name="sequence">The sequence of starting elements.</param>
/// <returns>The sequences starting with the specified sequence.</returns>
public new IEnumerable<string> StartingWith(char[] sequence)
{
return base.StartingWith(this.CaseSensitive ? sequence : this.ToUpper(sequence)).Select(i => new String(i));
}

/// <summary>
/// Gets the enumerator.
/// </summary>
/// <returns>The enumerator.</returns>
public new IEnumerator<string> GetEnumerator()
{
foreach (var item in this.Items)
{
yield return item;
}
}

IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
}
8 changes: 5 additions & 3 deletions SharpBag/SharpBag.csproj
Expand Up @@ -75,6 +75,8 @@
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="Collections\TernarySearchTree.cs" />
<Compile Include="Collections\TernaryStringSearchTree.cs" />
<Compile Include="DisposableAction.cs" />
<Compile Include="CollectionExtensions.cs" />
<Compile Include="Collections\BinaryHeap.cs" />
Expand Down Expand Up @@ -112,10 +114,10 @@
<Compile Include="Math\ForFraction\ForBigInteger\Matrix.cs" />
<Compile Include="Math\ForFraction\ForBigInteger\Vector.cs" />
<Compile Include="Math\ForBigInteger\Fraction.cs" />
<Compile Include="Math\ForBigInteger\Polynomial.cs" />
<Compile Include="Math\ForComplex\Polynomial.cs" />
<Compile Include="Math\ForBigInteger\Polynomial.cs" />
<Compile Include="Math\ForComplex\Polynomial.cs" />
<Compile Include="Math\ForFraction\ForInt32\Matrix.cs" />
<Compile Include="Math\ForFraction\ForInt32\Vector.cs" />
<Compile Include="Math\ForFraction\ForInt32\Vector.cs" />
<Compile Include="Math\ForInt64\Polynomial.cs" />
<Compile Include="Math\ForInt32\Polynomial.cs" />
<Compile Include="Math\Geometry\Circle.cs" />
Expand Down
Binary file modified SharpBag/bin/Release/CodeContracts/SharpBag.Contracts.dll
Binary file not shown.
Binary file modified SharpBag/bin/Release/SharpBag.dll
Binary file not shown.

0 comments on commit 27fa308

Please sign in to comment.