Salah satu tantangan pengkodean yang paling menarik yang diberikan kepada saya untuk wawancara adalah membuat antrian fungsional. Syaratnya adalah bahwa setiap panggilan ke enqueue akan membuat antrian baru yang sesuai dengan antrian lama dan item baru di bagian ekor. Dequeue juga akan mengembalikan antrian baru dan item yang keluar sebagai param.
Membuat IEnumerator dari implementasi ini tidak merusak. Dan izinkan saya memberi tahu Anda menerapkan Antrian Fungsional yang berkinerja baik jauh lebih sulit daripada menerapkan Fungsional Stack yang performan (tumpukan Push / Pop keduanya bekerja pada Tail, untuk Antrian Enqueue bekerja pada ekor, dequeue bekerja di kepala).
Maksud saya ... ini sepele untuk membuat Stack Enumerator yang tidak rusak dengan mengimplementasikan mekanisme Pointer Anda sendiri (StackNode <T>) dan menggunakan semantik fungsional di Enumerator.
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;
}
}
}
Beberapa hal yang perlu diperhatikan. Panggilan untuk mendorong atau pop sebelum pernyataan saat ini = _head; selesai akan memberi Anda tumpukan yang berbeda untuk enumerasi daripada jika tidak ada multithreading (Anda mungkin ingin menggunakan ReaderWriterLock untuk melindungi ini). Saya membuat bidang di StackNode hanya untuk dibaca tetapi tentu saja jika T adalah objek yang bisa berubah, Anda dapat mengubah nilainya. Jika Anda membuat konstruktor Stack yang menggunakan StackNode sebagai parameter (dan atur head ke yang dilewatkan dalam node). Dua tumpukan yang dibangun dengan cara ini tidak akan berdampak satu sama lain (dengan pengecualian T yang bisa berubah seperti yang saya sebutkan). Anda dapat Push dan Pop semua yang Anda inginkan dalam satu tumpukan, yang lain tidak akan berubah.
Dan bahwa teman saya adalah bagaimana Anda melakukan penghitungan Stack yang tidak merusak.