a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
300 lines
7.7 KiB
C#
300 lines
7.7 KiB
C#
//-- 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<T>, IEnumerator<T>
|
|
|
|
public delegate R Mapper<A,R>(A x);
|
|
|
|
public interface IMyList<T> : IEnumerable<T> {
|
|
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<U> Map<U>(Mapper<T,U> f); // Map f over all elements
|
|
}
|
|
|
|
public class LinkedList<T> : IMyList<T> {
|
|
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; i<n; i++)
|
|
node = node.next;
|
|
return node;
|
|
} else { // Closer to end
|
|
Node node = last;
|
|
for (int i=size-1; i>n; 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<T>)that).Count) {
|
|
Node thisnode = this.first;
|
|
IEnumerator<T> thatenm = ((IMyList<T>)that).GetEnumerator();
|
|
while (thisnode != null) {
|
|
if (!thatenm.MoveNext())
|
|
throw new ApplicationException("Impossible: LinkedList<T>.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>(T[] arr) {
|
|
return new LinkedList<T>(arr);
|
|
}
|
|
|
|
public static LinkedList<T> operator +(LinkedList<T> xs1, LinkedList<T> xs2) {
|
|
LinkedList<T> res = new LinkedList<T>();
|
|
foreach (T x in xs1)
|
|
res.Add(x);
|
|
foreach (T x in xs2)
|
|
res.Add(x);
|
|
return res;
|
|
}
|
|
|
|
public IMyList<U> Map<U>(Mapper<T,U> f) {
|
|
LinkedList<U> res = new LinkedList<U>();
|
|
foreach (T x in this)
|
|
res.Add(f(x));
|
|
return res;
|
|
}
|
|
|
|
public IEnumerator<T> GetEnumerator() {
|
|
return new LinkedListEnumerator(this);
|
|
}
|
|
|
|
IEnumerator IEnumerable.GetEnumerator() {
|
|
return new LinkedListEnumerator(this);
|
|
}
|
|
|
|
private class LinkedListEnumerator : IEnumerator<T> {
|
|
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<T> 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<T> : LinkedList<T> where T : IComparable<T> {
|
|
// 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<T> : LinkedList<T>, 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<MyString> {
|
|
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<double> dLst = new LinkedList<double>(7.0, 9.0, 13.0, 0.0);
|
|
foreach (double d in dLst)
|
|
Console.Write("{0} ", d);
|
|
Console.WriteLine();
|
|
IMyList<int> iLst =
|
|
dLst.Map<int>(new Mapper<double, int>(Math.Sign));
|
|
foreach (int i in iLst)
|
|
Console.Write("{0} ", i);
|
|
Console.WriteLine();
|
|
IMyList<String> sLst =
|
|
dLst.Map<String>(delegate(double d) { return "s" + d; });
|
|
foreach (String s in sLst)
|
|
Console.Write("{0} ", s);
|
|
Console.WriteLine();
|
|
// Testing SortedList<MyString>
|
|
SortedList<MyString> sortedLst = new SortedList<MyString>();
|
|
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();
|
|
}
|
|
}
|