SORU
24 Mart 2012, CUMARTESİ


Neden SortedSet<T>.Değil't O(log N) GetViewBetween?

.NET 4.0 , SortedSet<T> yöntemi vardır sınıf bir ağaç parçası ikisi arasındaki tüm değerleri belirtilen içeren bir arayüz görünüm verir GetViewBetween(l, r) denir. SortedSet<T> kırmızı-siyah ağaç olarak uygulandığı göz önüne alındığında, ben doğal olarak O(log N) zaman çalıştırmak için bekliyoruz. C benzer bir yöntem Java TreeSet.headSet/tailSet ve logaritmik std::set::lower_bound/upper_bound.

Ancak, bu doğru değil. Aşağıdaki kodu GetViewBetween O(log N) sürüm bu kod 1-2 sn içinde kestirecek eşdeğer ise 32 saniye çalışır.

var s = new SortedSet<int>();
int n = 100000;
var rand = new Random(1000000007);
int sum = 0;
for (int i = 0; i < n;   i) {
    s.Add(rand.Next());
    if (rand.Next() % 2 == 0) {
        int l = rand.Next(int.MaxValue / 2 - 10);
        int r = l   rand.Next(int.MaxValue / 2 - 10);
        var t = s.GetViewBetween(l, r);
        sum  = t.Min;
    }
}
Console.WriteLine(sum);

System.dll dotPeek ve burada var ve ne derlenmiş halini açtım:

public TreeSubSet(SortedSet<T> Underlying, T Min, T Max, bool lowerBoundActive, bool upperBoundActive)
    : base(Underlying.Comparer)
{
    this.underlying = Underlying;
    this.min = Min;
    this.max = Max;
    this.lBoundActive = lowerBoundActive;
    this.uBoundActive = upperBoundActive;
    this.root = this.underlying.FindRange(this.min, this.max, this.lBoundActive, this.uBoundActive);
    this.count = 0;
    this.version = -1;
    this.VersionCheckImpl();
}

internal SortedSet<T>.Node FindRange(T from, T to, bool lowerBoundActive, bool upperBoundActive)
{
  SortedSet<T>.Node node = this.root;
  while (node != null)
  {
    if (lowerBoundActive && this.comparer.Compare(from, node.Item) > 0)
    {
      node = node.Right;
    }
    else
    {
      if (!upperBoundActive || this.comparer.Compare(to, node.Item) >= 0)
        return node;
      node = node.Left;
    }
  }
  return (SortedSet<T>.Node) null;
}

private void VersionCheckImpl()
{
    if (this.version == this.underlying.version)
      return;
    this.root = this.underlying.FindRange(this.min, this.max, this.lBoundActive, this.uBoundActive);
    this.version = this.underlying.version;
    this.count = 0;
    base.InOrderTreeWalk((TreeWalkPredicate<T>) (n =>
    {
      SortedSet<T>.TreeSubSet temp_31 = this;
      int temp_34 = temp_31.count   1;
      temp_31.count = temp_34;
      return true;
    }));
}

Yani, FindRange belli ki ** 16 yaşında, ama bundan sonra düğümlerini anlatırken sadece bulundu alt doğrusal zamanlı bir geçiş yapar VersionCheckImpl... diyoruz!

  1. Neden bu geçişi her zaman yapmak zorunda mısın?
  2. Neden .NET anahtar gibi C ya da Java tabanlı bölme O(log N) bir yöntem bir ağaç içermiyor?gerçektendurumlar çok yararlı.

CEVAP
30 Mart 2012, Cuma


version alanla ilgili

UPDATE1:

Hafızam, bir sürü(belki?) KÜÇÜK koleksiyonlar 20* *alan var.

Önce foreach hakkında:

msdn link buna göre

Foreach deyimi bir dizi ya da bir nesne koleksiyonundaki her öğe için gömülü bir grup ifadeleri tekrarlar. Foreach deyimi koleksiyonu istenen bilgileri almak için yinelemek kullanılır, ama koleksiyon içeriğini öngörülemeyen yan etkileri önlemek için değiştirmek için kullanılmamalıdır.

Diğer birçok koleksiyonları korunmaktadır verileri foreach sırasında değiştirilmez

Örneğin, HashTable25**:

public virtual bool MoveNext()
{
    if (this.version != this.hashtable.version)
    {
        throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion"));
    }
    ..........
}

Ama SortedSet<T>'MoveNext() yöntem:

public bool MoveNext()
{
    this.tree.VersionCheck();
    if (this.version != this.tree.version)
    {
        ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
    }       
    ....
}

UPDATE2: bir

Ama O(N) belki de sadece Count özelliği version için değil, aynı zamanda döngü.

MSDN of GetViewBetween dediği için:

Bu yöntem karşılaştırıcısı tarafından tanımlanan lowerValue ve upperValue arasında kalan elemanları aralığının bir görünüm verir, ....Görünümü ve temel SortedSet(T) hem de değişiklik yapabilirsiniz.

Her güncelleştirme için eşitleme olmalı count alanı (anahtar ve değer zaten aynı). Emin Count yapmak doğru değildir

Hedefe ulaşmak için iki ilke vardı:

  1. Microsoft
  2. Mono

İlk.MS,kendi kodu, GetViewBetween()'nın performansı ve Count Tesisin performansını kazanmak. kurban

VersionCheckImpl() Count özelliği senkronize etmek için tek yoldur.

İkinci Olarak,Mono. GetCount()kendi yöntemi mono,GetViewBetween() kodu daha Hızlı, ama:

internal override int GetCount ()
{
    int count = 0;
    using (var e = set.tree.GetSuffixEnumerator (lower)) {
        while (e.MoveNext () && set.helper.Compare (upper, e.Current) >= 0)
              count;
    }
    return count;
}

Her zaman(N) işlemi!

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • 30GB

    30GB

    14 AĞUSTOS 2006
  • SRI International

    SRI Internat

    30 NİSAN 2008
  • whatever

    whatever

    30 EYLÜL 2005