[英]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字節),這可能不是很簡單
它增加了復雜性,使這些字段在Add
和Remove
保持最新
它將樹可以容納的最大元素數限制為用於計數的數據類型的大小。
如果您對這些權衡沒有問題,您可以這樣做:您在每個節點中保留該子樹中元素的數量。 如果索引大於左側樹中的計數,則索引位於右側子樹中,如果索引較低,則索引位於左側樹中,如果索引等於左子樹中的計數,則表示搜索索引是當前元素。 如果我們繼續使用正確的樹,我們需要將索引調整為相對於右子樹的索引。
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.