Một trong những thử thách mã hóa thú vị nhất được đưa ra cho tôi cho một cuộc phỏng vấn là tạo ra một hàng đợi chức năng. Yêu cầu là mỗi lệnh gọi enqueue sẽ tạo ra một hàng đợi mới bao gồm hàng đợi cũ và mục mới ở đuôi. Dequeue cũng sẽ trả lại một hàng đợi mới và vật phẩm bị mất như là một thông số.
Tạo một IEnumerator từ việc thực hiện này sẽ là không phổ biến. Và để tôi nói với bạn rằng việc thực hiện Hàng đợi chức năng hoạt động tốt khó khăn hơn rất nhiều so với việc thực hiện Ngăn chức năng biểu diễn (stack Push / Pop đều hoạt động trên Đuôi, vì Queue Enqueue hoạt động ở phần đuôi, dequeue hoạt động trên đầu).
Quan điểm của tôi là ... thật đơn giản để tạo ra một Trình liệt kê ngăn xếp không phá hủy bằng cách thực hiện cơ chế Con trỏ của riêng bạn (StackNode <T>) và sử dụng ngữ nghĩa chức năng trong Trình liệt kê.
public class Stack<T> implements IEnumerator<T>
{
private class StackNode<T>
{
private readonly T _data;
private readonly StackNode<T> _next;
public StackNode(T data, StackNode<T> next)
{
_data=data;
_next=next;
}
public <T> Data{get {return _data;}}
public StackNode<T> Next{get {return _Next;}}
}
private StackNode<T> _head;
public void Push(T item)
{
_head =new StackNode<T>(item,_head);
}
public T Pop()
{
//Add in handling for a null head (i.e. fresh stack)
var temp=_head.Data;
_head=_head.Next;
return temp;
}
///Here's the fun part
public IEnumerator<T> GetEnumerator()
{
//make a copy.
var current=_head;
while(current!=null)
{
yield return current.Data;
current=_head.Next;
}
}
}
Một số điều cần lưu ý. Một cuộc gọi để đẩy hoặc bật trước câu lệnh current = _head; hoàn thành sẽ cung cấp cho bạn một ngăn xếp khác để liệt kê so với khi không có đa luồng (bạn có thể muốn sử dụng ReaderWriterLock để bảo vệ chống lại điều này). Tôi đã thực hiện các trường trong StackNode chỉ đọc nhưng tất nhiên nếu T là một đối tượng có thể thay đổi, bạn có thể thay đổi giá trị của nó. Nếu bạn định tạo một hàm tạo Stack lấy một StackNode làm tham số (và đặt đầu vào đó được truyền trong nút). Hai ngăn xếp được xây dựng theo cách này sẽ không tác động lẫn nhau (ngoại trừ chữ T có thể thay đổi như tôi đã đề cập). Bạn có thể Đẩy và bật tất cả những gì bạn muốn trong một ngăn xếp, cái kia sẽ không thay đổi.
Và bạn của tôi là cách bạn thực hiện phép liệt kê không phá hủy của Stack.