繁体   English   中英

二叉搜索树的索引器

[英]indexator of binary search tree

我创建了一个二叉搜索树。 我需要实现一个索引器,它可以帮助我获取树的元素,但它必须是排序序列的一部分。 当然,我可以做点什么

public T this[int i]
        {
            get
            {
                var list = this.ToList();
                return list[i];
            }
        }

因为我已经实现了公共IEnumerator<T> GetEnumerator() ,它获取了排序序列,但是如果我有很多调用那么它使用起来很慢

for(int i = 0; i < 10000000; i++)
{
    tree.Add(i);
    Console.Write(tree[i]);
}

我想优化这个任务。 怎么样? 完整代码:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace BinaryTrees
{
    public class BinaryTree<T> : IEnumerable<T>
        where T : IComparable

    {
        private Node root;
        public int Count { get; private set; }

        public class Node
        {
            public Node left, right;
            public T value;
        }

        public BinaryTree()
        {
            root = new Node();
        }

        public T this[int i]
        {
            get
            {
                var list = this.ToList(); 
                                          //How to 
                                          //make it fast??
                return list[i];
            }
        }

        public void Add(T key)
        {
            var current = root;

            while (true)
            {
                if (Count == 0)
                {
                    current.value = key;
                    Count++;
                    break;
                }

                if (key.CompareTo(current.value) <= 0)
                {
                    if (current.left == null)
                    {
                        current.left = new Node { value = key };
                        Count++;
                        break;
                    }
                    else
                        current = current.left;
                }

                if (key.CompareTo(current.value) > 0)
                {
                    if (current.right == null)
                    {
                        current.right = new Node { value = key };
                        Count++;
                        break;
                    }
                    else
                        current = current.right;
                }
            }
        }

        public bool Contains(T key)
        {
            var current = root;
            while (true)
            {
                if (Count == 0)
                    return false;

                if (current == null)
                    return false;

                var result = key.CompareTo(current.value);

                if (result == 0)
                    return true;

                if (result < 0)
                {
                    current = current.left;
                }
                else if (result > 0)
                {
                    current = current.right;
                }
            }
        }

        public IEnumerator<T> GetEnumerator()
        {
            var stack = new Stack<Node>();

            var current = root;

            var done = false;

            while (!done)
            {
                if (current != null)
                {
                    stack.Push(current);
                    current = current.left;
                }

                else if (stack.Count != 0)
                {
                    current = stack.Pop();

                    yield return current.value;

                    current = current.right;
                }

                else done = true;
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
}

我想,也许我可以创建一个数组,我可以在索引器中对其进行排序,就像我添加了一个元素一样,但我意识到这也是一个坏主意。

最简单的解决方案是尽可能避免索引。 如果您已经拥有枚举器,并且需要索引,请手动保留它,并且不要编制索引。 如果插入后需要节点,请从add方法返回:

int index =0;
foreach (var item in tree)
{
    Console.WriteLine($"At {index} - {item}");
    index++;
}

如果无法做到这一点,优化索引访问需要使用额外的内存来跟踪树的每个分支上有多少个节点并使用此信息进行索引。 这有几个副作用:

  • 它通过Count字段的字节Count增加Node对象的大小(例如int - 4字节),这可能不是很简单

  • 它增加了复杂性,使这些字段在AddRemove保持最新

  • 它将树可以容纳的最大元素数限制为用于计数的数据类型的大小。

如果您对这些权衡没有问题,您可以这样做:您在每个节点中保留该子树中元素的数量。 如果索引大于左侧树中的计数,则索引位于右侧子树中,如果索引较低,则索引位于左侧树中,如果索引等于左子树中的计数,则表示搜索索引是当前元素。 如果我们继续使用正确的树,我们需要将索引调整为相对于右子树的索引。

public class BinaryTree<T> : IEnumerable<T>
   where T : IComparable

{
    private Node root;
    public int Count { get; private set; }

    public class Node
    {
        public int count;
        public Node left, right;
        public T value;
    }

    public BinaryTree()
    {
        root = new Node();
    }

    public T this[int i]
    {
        get
        {
            var current = this.root;
            while (true)
            {
                int beforeCount = current.left?.count ?? 0;
                if (beforeCount == i ) return current.value;

                if (beforeCount < i)
                {
                    i = i - beforeCount - 1;
                    current = current.right;
                }
                else
                {
                    current = current.left;
                }
            }
        }
    }


    public void Add(T key)
    {
        var current = root;
        if (Count == 0)
        {
            current.value = key;
            current.count = 1;
            Count++;
            return;
        }
        while (true)
        {
            current.count++;
            if (key.CompareTo(current.value) <= 0)
            {
                if (current.left == null)
                {
                    current.left = new Node { value = key, count = 1 };
                    Count++;
                    break;
                }
                else
                {
                    current = current.left;
                }
            }
            else if (key.CompareTo(current.value) > 0)
            {
                if (current.right == null)
                {
                    current.right = new Node { value = key, count = 1 };
                    Count++;
                    break;
                }
                else
                {
                    current = current.right;
                }
            }

        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM