//-- ex-gen-class-linkedlist //-- ex-anonymous-method-linkedlist //-- ex-gen-printable //-- ex-gen-interface-ilist //-- ex-gen-linkedlist-map //-- ex-gen-linkedlistenumerator //-- ex-gen-delegate-fun // A generic LinkedList class using System; using System.IO; // TextWriter using System.Collections; using System.Collections.Generic; // IEnumerable, IEnumerator public delegate R Mapper(A x); public interface IMyList : IEnumerable { int Count { get; } // Number of elements T this[int i] { get; set; } // Get or set element at index i void Add(T item); // Add element at end void Insert(int i, T item); // Insert element at index i void RemoveAt(int i); // Remove element at index i IMyList Map(Mapper f); // Map f over all elements } public class LinkedList : IMyList { protected int size; // Number of elements in the list protected Node first, last; // Invariant: first==null iff last==null protected class Node { public Node prev, next; public T item; public Node(T item) { this.item = item; } public Node(T item, Node prev, Node next) { this.item = item; this.prev = prev; this.next = next; } } public LinkedList() { first = last = null; size = 0; } public LinkedList(params T[] arr) : this() { foreach (T x in arr) Add(x); } public int Count { get { return size; } } public T this[int i] { get { return get(i).item; } set { get(i).item = value; } } private Node get(int n) { if (n < 0 || n >= size) throw new IndexOutOfRangeException(); else if (n < size/2) { // Closer to front Node node = first; for (int i=0; in; i--) node = node.prev; return node; } } public void Add(T item) { Insert(size, item); } public void Insert(int i, T item) { if (i == 0) { if (first == null) // and thus last == null first = last = new Node(item); else { Node tmp = new Node(item, null, first); first.prev = tmp; first = tmp; } size++; } else if (i == size) { if (last == null) // and thus first = null first = last = new Node(item); else { Node tmp = new Node(item, last, null); last.next = tmp; last = tmp; } size++; } else { Node node = get(i); // assert node.prev != null; Node newnode = new Node(item, node.prev, node); node.prev.next = newnode; node.prev = newnode; size++; } } public void RemoveAt(int i) { Node node = get(i); if (node.prev == null) first = node.next; else node.prev.next = node.next; if (node.next == null) last = node.prev; else node.next.prev = node.prev; size--; } public override bool Equals(Object that) { if (that != null && GetType() == that.GetType() && this.size == ((IMyList)that).Count) { Node thisnode = this.first; IEnumerator thatenm = ((IMyList)that).GetEnumerator(); while (thisnode != null) { if (!thatenm.MoveNext()) throw new ApplicationException("Impossible: LinkedList.Equals"); // assert MoveNext() was true (because of the above size test) if (!thisnode.item.Equals(thatenm.Current)) return false; thisnode = thisnode.next; } // assert !MoveNext(); // because of the size test return true; } else return false; } public override int GetHashCode() { int hash = 0; foreach (T x in this) hash ^= x.GetHashCode(); return hash; } public static explicit operator LinkedList(T[] arr) { return new LinkedList(arr); } public static LinkedList operator +(LinkedList xs1, LinkedList xs2) { LinkedList res = new LinkedList(); foreach (T x in xs1) res.Add(x); foreach (T x in xs2) res.Add(x); return res; } public IMyList Map(Mapper f) { LinkedList res = new LinkedList(); foreach (T x in this) res.Add(f(x)); return res; } public IEnumerator GetEnumerator() { return new LinkedListEnumerator(this); } IEnumerator IEnumerable.GetEnumerator() { return new LinkedListEnumerator(this); } private class LinkedListEnumerator : IEnumerator { T curr; // The enumerator's current element bool valid; // Is the current element valid? Node next; // Node holding the next element, or null public LinkedListEnumerator(LinkedList lst) { next = lst.first; valid = false; } public T Current { get { if (valid) return curr; else throw new InvalidOperationException(); } } object IEnumerator.Current { get { return Current; } } public bool MoveNext() { if (next != null) { curr = next.item; next = next.next; valid = true; } else valid = false; return valid; } public void Reset() { throw new NotImplementedException (); } public void Dispose() { curr = default(T); next = null; valid = false; } } } class SortedList : LinkedList where T : IComparable { // Sorted insertion public void Insert(T x) { Node node = first; while (node != null && x.CompareTo(node.item) > 0) node = node.next; if (node == null) // x > all elements; insert at end Add(x); else { // x <= node.item; insert before node Node newnode = new Node(x); if (node.prev == null) // insert as first element first = newnode; else node.prev.next = newnode; newnode.next = node; newnode.prev = node.prev; node.prev = newnode; } } } interface IPrintable { void Print(TextWriter fs); } class PrintableLinkedList : LinkedList, IPrintable where T : IPrintable { public void Print(TextWriter fs) { bool firstElement = true; foreach (T x in this) { x.Print(fs); if (firstElement) firstElement = false; else fs.Write(", "); } } } class MyString : IComparable { private readonly String s; public MyString(String s) { this.s = s; } public int CompareTo(MyString that) { return String.Compare(that.Value, s); // Reverse ordering } public bool Equals(MyString that) { return that.Value == s; } public String Value { get { return s; } } } class MyTest { public static void Main(String[] args) { LinkedList dLst = new LinkedList(7.0, 9.0, 13.0, 0.0); foreach (double d in dLst) Console.Write("{0} ", d); Console.WriteLine(); IMyList iLst = dLst.Map(new Mapper(Math.Sign)); foreach (int i in iLst) Console.Write("{0} ", i); Console.WriteLine(); IMyList sLst = dLst.Map(delegate(double d) { return "s" + d; }); foreach (String s in sLst) Console.Write("{0} ", s); Console.WriteLine(); // Testing SortedList SortedList sortedLst = new SortedList(); sortedLst.Insert(new MyString("New York")); sortedLst.Insert(new MyString("Rome")); sortedLst.Insert(new MyString("Dublin")); sortedLst.Insert(new MyString("Riyadh")); sortedLst.Insert(new MyString("Tokyo")); foreach (MyString s in sortedLst) Console.Write("{0} ", s.Value); Console.WriteLine(); } }