C#指针、迭代器和泛型
本文关键字:泛型 迭代器 指针 | 更新日期: 2023-09-27 18:23:37
我被难住了
如何在C#中像使用C++迭代器一样使用迭代器?我找不到Begin()或End()访问器,甚至找不到如何声明迭代器。我读过关于分子的书。我的目标是实现合并函数。这是我用C++编写的Merge函数的一部分。大多数情况下,我正在寻找与所示内容等效的C#,只是我将使用引用类型而不是整数。
void merge(vector<int>::iterator left, vector<int>::iterator right, vector<int>::iterator leftEnd, vector<int>::iterator rightEnd, vector<int>::iterator full)
{
while(left != leftEnd && right!= rightEnd) //compare left and right until the end of the vector is reached
{
if(*right < *left) //right < left so insert right to the output vector and advance the iterators
{
*full++ = *right++;
}
else //left < right so insert left to the output vector and advance the iterators
{
*full++ = *left++;
}
}
while(left != leftEnd) //copy any remaining elements into the output from left
{
*full++ = *left++;
}
}
此外,我应该使用哪些集合?(目前我一直在尝试List<T>
和LinkedList<T>
)。
听起来你想要这样的东西:
bool leftValid = left.MoveNext();
bool rightValid = right.MoveNext();
while (leftValid && rightValid)
{
if (right.Current < left.Current)
{
full.Add(right.Current);
rightValid = right.MoveNext();
}
else
{
full.Add(left.Current);
leftValid = left.MoveNext();
}
}
while (leftValid)
{
full.Add(left.Current);
leftValid = left.MoveNext();
}
while (rightValid)
{
full.Add(right.Current);
rightValid = right.MoveNext();
}
这里full
需要是某种IList<T>
-.NET迭代器不允许您对底层集合进行更改。
您不应该试图编写"桥接"代码来使用像C++那样的.NET迭代器;当您使用.NET.时,最好尝试从.NET迭代器的角度开始思考
请注意,在.NET中传递迭代器是非常罕见的。将方法设置为IEnumerable<T>
参数会更自然,并执行以下操作:
using (IEnumerable<T> leftIterator = leftSequence.GetEnumerator())
{
using (IEnumerable<T> rightIterator = rightSequence.GetEnumerator())
{
// Code as above, just using leftIterator and rightIterator
// instead of left and right
}
}
.net容器不支持C++风格的迭代器。他们只有
- 称为
IEnumerator<T>
的简单前向迭代器 - 无法修改集合
- 不是随机访问
- 无法复制(有些集合具有可以复制的值类型迭代器,但这是一项棘手的业务,很少使用)
- 在大多数集合上,每当修改集合时也会失效
它们几乎唯一能做的就是在foreach
语句中进行迭代。
您可能想了解IList<T>
接口,它允许随机访问,但仅在支持快速索引的集合上受支持。在这样的集合上,您可以通过使用索引来实现就地合并排序。
void Merge<T>(IList<T> container,int left, int right, int leftEnd, int rightEnd, int full)
然后使用CCD_ 9而不是CCD_。
不幸的结果是,您无法实现像C++那样高效的容器无关的就地排序函数。
我认为您想要GetEnumerator()、MoveNext()和Current。
通常,您可以只使用foreach进行迭代,但您的情况很特殊。
如果事实是这样的话,与其使用"full",不如将其组织为迭代器块,并惰性地合并两个枚举。
IEnumerable<T> Merge<T>(IEnumerable<T> left, IEnumerable<T> right)
{
... yield return Min<T>(left.Current, right.Current); ..,
}
您可以使用具有固定大小的数组,也可以使用List<T>
,在其他语言中也称为ArrayLists。它们的项目可以通过索引器(list[i]
)访问,并且项目可以附加list.Add(item);
。它们会自动生长。LinkedLists
不能通过索引器访问,必须遍历。
你可以像这个一样声明方法
void merge(IEnumerator<int> left, IEnumerator<int> right,
List<int> full)
{
// Jon Skeet's code goes here
}
你可以得到一个像这样的枚举器
IEnumerable<int> intEnumerable = ...;
IEnumerator<int> intEnumerator = intEnumerable.GetEnumerator();
IEnumerable<T>
是由大多数通用集合类型实现的。非泛型集合通常实现IEnumerable
。
(针对@CodeInChaos的评论进行了编辑)。