这几乎就是juharr 在单链表的评论中建议您的内容。
GetMiddle 从列表的头部开始,rightPointer 向前看两个元素,leftPointer 看下一个元素(两个指针向同一方向移动)。最后,当没有更多元素要检查时,leftPointer 是列表的中间节点。
在下面的代码中Node 是一个单链表节点,List 只是将元素添加到列表中并暴露其head。
public T GetMiddle<T>(List<T> list)
{
Node<T> leftPointer = list.Head;
Node<T> rightPointer = list.Head;
while (rightPointer != null && rightPointer.Next != null)
{
rightPointer = rightPointer.Next.Next;
leftPointer = leftPointer.Next;
}
return leftPointer.Item;
}
public class List<T>
{
public Node<T> Head { get; private set; }
private Node<T> Last;
public void Add(T value)
{
Node<T> oldLast = Last;
Last = new Node<T>(value);
if (Head == null)
{
Head = Last;
}
else
{
oldLast.Next = Last;
}
}
}
public class Node<T>
{
public T Item { get; private set; }
public Node<T> Next { get; set; }
public Node(T item)
{
Item = item;
}
}
如果是偶数个元素,比如[1, 9]
var list = new List<int>();
foreach (var number in Enumerable.Range(1, 9))
{
list.Add(number);
}
Console.WriteLine(GetMiddle(list));
中间元素是5。
但是,如果元素数量为偶数,[1, 10] 行,算法将产生6。这是因为当right 位于9 时,下一个不是null 而是10。所以当我们完成这个迭代时,right 指向null,left 指向6(我们返回中间)。
right: 1 -> 3 -> 5 -> 7 -> 9 -> null | end
left: 1 -> 2 -> 3 -> 4 -> 5 -> 6 | end
这意味着即使在这种情况下,您也需要决定将哪个元素作为中间元素 - 5 或 6。如果您想要 5,则需要在循环中添加一个额外的条件:
rightPointer = rightPointer.Next.Next;
if (rightPointer != null)
{
leftPointer = leftPointer.Next;
}