我正在尝试按顺序创建一个通用"插入" C#中的算法,可以实现以下
/// <summary>
/// Inserts a new element in its proper order into an ordered enumeration
/// </summary>
/// <typeparam name="T">The comparable type</typeparam>
/// <param name="source">The sorted enumeration</param>
/// <param name="insertion">The element to insert</param>
/// <returns>A new enumeration with <paramref name="insertion"/> in its proper order</returns>
public static IEnumerable<T> InsertInOrder<T>(this IEnumerable<T> source, T insertion) where T : IComparable<T>
{
throw new NotImplementedException();
}
并在操作次数和内存方面尽可能优化。我遇到的主要问题是,在使用MoveNext()
时,在我的算法中始终存在这些情况,其中我偶然发现了#34;可能已经移动太远,并希望恢复前一个元素。这让我很难写出最优雅的东西。
为了在O(n)时间内看起来优雅,而不是直接使用enumereator我想出了
IEnumerable<T> smallers = source.TakeWhile(x => x.CompareTo(insertion) < 0);
IEnumerable<T> greaters = source.SkipWhile(x => x.CompareTo(insertion) >= 0);
IEnumerable<T> reordered = smallers.Concat(new[] { insertion }).Concat(greaters);
foreach (T element in reordered)
{
yield return element;
}
但由于source
上有多次枚举,因此效率不高。
所以我尝试转换为单枚举,最终(虽然它让我感到尴尬多久)想出了
bool inserted = false;
IEnumerator<T> mover = source.GetEnumerator();
while (mover.MoveNext())
{
if (mover.Current.CompareTo(insertion) < 0)
{
yield return mover.Current;
}
else
{
if (!inserted)
{
yield return insertion;
inserted = true;
}
yield return mover.Current;
}
}
但问题是,一旦我们到达列表中insertion
小于或等于mover.Current
的点,if (mover.Current.CompareTo(insertion) < 0)
就变成无用的检查。
所以,最终我想出了
bool movedNext;
IEnumerator<T> mover = source.GetEnumerator();
while (movedNext = mover.MoveNext() && mover.Current.CompareTo(insertion) < 0)
{
yield return mover.Current;
}
yield return insertion;
if (movedNext)
{
do
{
yield return mover.Current;
} while (mover.MoveNext());
}
但是仍然存在额外变量moveNext
并且不得不一遍又一遍地重新分配它movedNext = mover.MoveNext()
的效率低下。
是否有可能在没有额外变量的情况下编写此插入算法来处理&#34;可能的额外移动&#34;? :)
答案 0 :(得分:1)
最后一点代码就像它能得到的一样好。不要再担心额外的#include <memory>
struct Obj
{
};
void f(const Obj &o)
{
std::shared_ptr<const Obj> optr(&o, [](const Obj*){});
}
变量和movedNext
循环内的赋值等无效率低下的问题。
现在,如果你的问题是简单的专业好奇,是否可以避免?然后答案是:是的,当然!但是(总有一个但是)付出代价: goto 进入,可读性退出:
while
我会付出千倍的低效率......