使用字符串参数和泛型类型T

时间:2018-04-13 10:12:59

标签: c# binary-search-tree

因此,我尝试搜索填充了节点中Country对象的二叉树T DataCountry对象的String变量包含国家/地区的名称(countryName),我想在文本框中搜索countryName并返回一个布尔值。因此,它将遍历Country个对象的二叉树,并将文本框字段中的值与countryName匹配。可以将对象的值分别存储在节点中,但我更倾向于使用泛型类型。以下是我的搜索方法。

public Boolean Contains(T item)
{
    return contains(item, ref root);
}

private Boolean contains(T item, ref Node<T> tree)
{
    if (tree != null)
    {
        if (item.CompareTo(tree.Data)==0)
        {
            Console.WriteLine("Found");
            return true;
        }
        return contains(item, ref tree.Left) || contains(item, ref tree.Right);
    }
    else
    {
        return false;
    }
}

节点结构

public T Data;
public Node<T> Left;
public Node<T> Right;
public int balanceFactor;
public Node(T Data)
{
    this.Data = Data;
    Left = null;
    Right = null;
}

2 个答案:

答案 0 :(得分:0)

从不调用自身内部的函数,这最终会导致StackOverflowException。你应该做这样的事情;

Depth First Search使用Stack<T>

static bool Contains<T>(T item, Node<T> tree) {
    Stack<Node<T>> stack = new Stack<Node<T>>();

    stack.Push(tree); //Push the root node into the stack

    Node<T> current;
    do {
        current = stack.Pop(); //Get the last item that was added to the stack and remove it at the same time

        if (item.Equals(current.Data)) //If the item we just popped has its 'Data' property equal to the 'item'
        {
            Console.WriteLine("Found");
            return true; //then return true
        }

        //Otherwise add the left and right nodes to the stack if they exist.
        if(current.Left != null) stack.Push(current.Left);
        if(current.Right != null) stack.Push(current.Right);
    } while(stack.Count > 0); //If the stack still contains items, go back to the 'do'

    //If we've reached this point we've searched the entire tree and found nothing
    return false;
}

Dotnetfiddle usage example

当你在程序中执行一个函数时,程序需要一些存储位置的方法,这称为堆栈。堆栈通常具有有限的大小,如果达到此限制并且您尝试进一步深度,则会抛出StackOverflowException。

基本上这就是你的功能在操作中的表现:

contains(contains(contains(contains(contains(contains(contains(contains(...

它必须考虑的深度级别通常不会出现在应用程序中,除非你做错了一些事情,比如在你自己内部调用一个函数,这就是你正在做的事情。

因此,不要让堆栈达到疯狂的深度,让我们只列出我们需要与我们搜索的内容进行比较的所有内容,并一路上将他们的孩子添加到同一个列表中。 / p>

这就是Stack<T>类型的用武之地。尽管堆栈类型与程序堆栈共享,但堆栈类型并不相同。 Stack类型只是一个项目列表,它可以添加(Push(T)),同时检索添加到列表中的最后一项,同时从列表中删除它({{1 }})。

因此,每次我们想要搜索节点时,我们不会将深度降低,而是在循环时将其添加到堆栈中。

答案 1 :(得分:0)

在二进制搜索树(BST)中,您必须以插入/搜索/删除项目时以相同排序顺序(使用相同比较器)的方式比较项目。您不能在插入中使用一个比较器(例如,比较国家/地区人口),而是在O(lg(N))中的同一个BST中按名称搜索。

为了构建允许您按名称搜索国家/地区的BST,请使用像Func<of T, of T, of int>这样的过程参数,或者在树构造函数中的.NET Framework IComparer<of T>中非常常见。请参见SortedSet<of T>类设计和SortedSet<of T>(IComparer<of T>)构造函数。

示例实施:

Node<T> _root;
readonly IComparer<T> _comparer;

public bool Contains(T target)
{
    return Contains(_root, target);
}

bool Contains(Node<T> root, T target)
{
    if (root == null)
        return false;
    int cmp = _comparer.Compare(target, root.Data);
    if (cmp == 0)
        return true;
    return cmp < 0 ? Contains(root.Left, target) : Contains(root.Right, target);
}

另请注意,在BST搜索实现中,仅在单个子树(左侧或右侧)上进行递归调用是非常重要的。

有关详细信息,请查看维基百科上的Binary search tree页面,SortedSet - custom order when storing a class object和有关StackOverflow的Using lambda expression in place of IComparer argument讨论。

相关问题