C # learning singly linked list and interfaces IList <T>

Author: Harry Own 
Time: 2015-11-04
Platform: Window7 64bit, Visual Studio Community 2015

reference:

chapter:

  • Singly linked list elements
  • User interface definitions singly linked list
  • The progressive realization of singly linked list

text:

Front learned IEnumerable <T>, IComparable <T>, ICollection <T> three interfaces, data structures, programming is to learn to use.

A unidirectional list element

The definition of a one-way linked list (Single Linked List), we know that Node list element includes a data element and the next NextNode two parts. Constructed as follows:

// list elements ===== way =====
class the Node <T>
{
    public the Value T;
    public the Node <T> NextNode;
}

The creation of this element should have no parameters () and parameters (T value) in two forms, we continue to make full code is as follows:

//=====单向链表元素=====
class Node<T>
{
    public T Value;
    public Node<T> NextNode;

    public Node():this(default(T)){ }
    public Node(T value)
    {
        Value = value;
        NextNode = null;
    }
}

Founded inside with no parameters have default (T), see the  default keyword MSDN generic code (C # Programming Guide) .

 

Second, the definition singly linked list user interface

With elements Node <T>, we want to operate it, the operation envisaged has to add, delete, modify, clear, traverse, index, etc., we take a look at the interface IColloction <T> and IList <T> agreement, it we know that to achieve IList <T>.

//======参考 IList<T>===
public interface IList<T> : ICollection<T>
{
    T this[int index] {get;set;}
    int IndexOf(T item);
    void Insert(int index, T item);
    void RemoveAt(int index);
}
//======参考 ICollection<T>===
public interface ICollection<T> : IEnumerable<T>
{
     int Count { get; }
     bool IsReadOnly { get; }
     void Add(T item);
     void Clear();
     bool Contains(T item);
     void CopyTo(T[] array, int arrayIndex);
     bool Remove(T item);
}

Third, the progressive realization of a one-way linked list

Define a singly linked list class:

===== way linked list // =====
public class SinglyLinkedList <T>: the IList <T>
{
}

The next election to achieve in a small yellow lightbulb Tip VS2015 IDE, so IDE help us fill in the blank it out. ^ _ ^ Long long list !, a total of 14 properties or methods need to fill (In my own experience little rookie, I absolutely had to fill up a class). We had no choice but to implement step by step down the class.

1, the first element is added. To introduce first element class Node <T>, named it head (the book is named, and I had remembered the name of the root), according to the wording of the new C # 6.0, we can direct it to the default value = null. Just start creating the list is empty inside, so the first element is null.

//=====单向链表=====
public class SinglyLinkedList<T> : IList<T>
{
    private Node<T> head = null;

2. Fill Add (T item) method and int Count {get;} property. Since this is a linked list, elements can only linear flow, so to add the elements one by one can only traverse to the end of the list most, we are here to add a count field int _count.

//=====单向链表=====
public class SinglyLinkedList<T> : IList<T>
{
    private Node<T> head = null;
    private int _count = 0;
    //---添加元素并计数
    public void Add(T item)
    {
        if (head == null)
        {
            head = new Node<T>(item);
            _count++;
        }
        else
        {
            Node<T> node = head;
            while (node.NextNode != null)
            {
                node = node.NextNode;
                _count++;
            }
            node.NextNode = new Node<T>(item);
        }
    }
    //---计数---
    public int Count
    {
        get { return _count; }
    }

Well, finally you can add elements and starts counting the experimental call to see if correct:

static void Main(string[] args)
{
    SinglyLinkedList<int> slist = new SinglyLinkedList<int>();
    Console.WriteLine($"count: {slist.Count}");
    slist.Add(1);
    slist.Add(2);
    slist.Add(3);
    slist.Add(4);
    Console.WriteLine($"count: {slist.Count}");

//输出结果:
//count: 0
//count: 4

3, to achieve enumerator that can traverse. After the can Add (T item), although they would join elements, but we can not be displayed inside the value is the number of elements, then it should implement IEnumerable <T> interface that allows it to traverse the display element values ​​inside.

// --- achieve enumerable
public the IEnumerator <T> the GetEnumerator ()
{
    the Node <T> = Node head;
    the Node <T> = new new the Node Result <T> ();
    the while (! Node = null)
    {
        Result = Node;
        Node = node.NextNode;
        the yield result.Value return;
    }
}
// --- do not fill, the above only calls
the IEnumerator IEnumerable.GetEnumerator ()
{
    the throw the NotImplementedException new new ();
}

The next call to see:

Console.Write("elements: ");
foreach (var s in slist) { Console.Write($"{s} "); }

//输出:
//elements: 1 2 3 4

4, to achieve emptied. As long as the head set to null, and the counter to zero. Here I can not help but think of this little rookie language no garbage collector, then how to release the memory occupied by the remaining elements, is first traversed by one release? Or the data is not placed on the heap? Well, my level too much time, not thinking beyond the capacity of things.

//---清空---
public void Clear()
{
    head = null;
    _count = 0;
}

5, to achieve specified Insert (int index, T item). It means to insert an element at the index position. Because it is a linked list, insert a new connection will destroy the entire value chain, we need to protect the site before inserting the new value that is saved on the element and the current element, then NextNode first element in completing the new element, fill in the current element in NextNode new element in, so the entire list and complete.

// --- intervening value ---
public void the Insert (int index, Item T)
{
    IF (index> = 0 && index <The _count)
    {
        the Node <T> = Node head;
        the Node <T> PREV = null;
        the Node <T> Next = null;
        // always head element head, so to get hold of special special index = 0
        IF (index == 0)
        {
            Next = head;
            head = new new the Node <T> (Item);
            head. Next = NextNode;
        }
        the else
        {
            for (int I = 0; I <index; I ++)
            {
                PREV = Node;
                Node = node.NextNode;
            }
            Next = Node;
            node = new Node<T>(item);
            node.NextNode = next;
            prev.NextNode = node;
        }
        _count++;
    }
    else throw new Exception("Out of Range !");
}

Call to check whether the right:

SinglyLinkedList<int> slist = new SinglyLinkedList<int>();
Console.WriteLine($"count: {slist.Count}");

slist.Add(1);
slist.Add(2);
slist.Add(3);
slist.Add(4);

Console.WriteLine($"count: {slist.Count}");
Console.Write("elements: ");
foreach (var s in slist) { Console.Write($"{s} "); }
Console.WriteLine();

slist.Insert(0, 5);
Console.Write("elements: ");
foreach (var s in slist) { Console.Write($"{s} "); }
Console.WriteLine();

Console.WriteLine($"count: {slist.Count}");
Console.ReadKey();


//输出:
count: 0
count: 4
elements: 1 2 3 4
elements: 5 1 2 3 4
count: 5

If even index = 0 can insert values, that our previous Add (T item) can be regarded as Insert (0, T item), but there are checks in Insert a index out of bounds, when the list is empty, Count = 0, it will throw an error. For this, we are Add (T item) before the first Count + 1, Insert and then go back to Count -1. Add reform are as follows:

// --- additive elements and counted
public void the Add (Item T)
{
    The _count ++;
    the Insert (The _count -. 1, Item);
    _count--;
}

6. Fill int IndexOf (T item) method. The latter method has int IndexOf (T item), bool Remove (T item), void RemoveAt (int index), bool Contains (T item) and an indexer, which are and find elements, whereas int IndexOf (T item) no doubt find a way to position elements, so we need to achieve it.
Another problem is that, to find T item, T must be comparable type, so we add a constraint on T SinglyLinkedList class is the IComparable <T> interface.

//=====单向链表=====
public class SinglyLinkedList<T> : IList<T> where T : IComparable<T>


//---查找---
public int IndexOf(T item)
{
    int result = -1;
    Node<T> node = head;
    for(int i = 0; i < _count; i++)
    {
        if (node.Value.Equals(item))
        {
            result = i;
            break;
        }
        node = node.NextNode;
    }
    return result;
}

With int IndexOf (T item) this weapon, some way down the fill in the blank is simple.

//---包含---
public bool Contains(T item)
{
    return IndexOf(item) > -1 ? true : false;
}
//---删除---
public void RemoveAt(int index)
{
    if (index >= 0 && index < _count)
    {
        Node<T> prev = null;
        Node<T> node = head;
        if (index == 0)
        {
            head = head.NextNode;
        }
        else
        {
            for (int i = 0; i < index; i++)
            {
                prev = node;
                node = node.NextNode;
            }
            prev.NextNode = node.NextNode;
        }
        _count--;
    }
    else throw new Exception("Out of Range !");
}
//---删除---
public bool Remove(T item)
{
    int n = IndexOf(item);
    if (n < 0) { return false; }
    RemoveAt(n);
    return true;
}

7, complete the indexer. Indexer see reference. Down concrete realization:

//---索引器
public T this[int index]
{
    get
    {
        if (index >= 0 && index < _count)
        {
            Node<T> node = head;
            for(int i = 0; i < index;i++)
            {
                node = node.NextNode;
            }
            return node.Value;
        }
        else throw new Exception("Out of Range !");
    }
    set
    {
        Insert(index,value);
    }
}

8, to achieve copy function:

//---拷贝
public void CopyTo(T[] array, int arrayIndex)
{
    Node<T> node = head;
    for(int i = 0; i < _count; i++)
    {
        array[arrayIndex + i] = node.Value;
        node = node.NextNode;
    }
}

At this point, the whole way linked list and IList <T> interface is learning well. Attached complete source code:

//=====单向链表=====
public class SinglyLinkedList<T> : IList<T> where T : IComparable<T>
{
    private Node<T> head = null;
    private int _count = 0;
    //---添加元素并计数---
    public void Add(T item)
    {
        _count++;
        Insert(_count - 1, item);
        _count--;
    }
    //---计数---
    public int Count
    {
        get { return _count; }
    }
    //---实现可枚举
    public IEnumerator<T> GetEnumerator()
    {
        Node<T> node = head;
        Node<T> result = new Node<T>();
        while (node != null)
        {
            result = node;
            node.NextNode = Node;
            the yield result.Value return;
        }
    }
    // --- do not fill, the above only calls
    the IEnumerator IEnumerable.GetEnumerator ()
    {
        the throw the NotImplementedException new new ();
    }
    // --- --- Empty
    public the Clear void ()
    {
        head = null;
        The _count = 0;
    }
    // --- intervening value ---
    public void the insert (int index, Item T)
    {
        IF (index> = 0 && index <The _count)
        {
            the Node <T > = Node head;
            the Node <T> PREV = null;
            the Node <T> Next = null;
            // always head element head, so to get hold of special special index = 0
            if (index == 0)
            {
                next = head;
                head = new Node<T>(item);
                head.NextNode = next;
            }
            else
            {
                for (int i = 0; i < index; i++)
                {
                    prev = node;
                    node = node.NextNode;
                }
                next = node;
                node = new Node<T>(item);
                node.NextNode = next;
                prev.NextNode = node;
            }
            _count++;
        }
        else throw new Exception("Out of Range !");
    }
    //---查找---
    public int IndexOf(T item)
    {
        int result = -1;
        Node<T> node = head;
        for (int i = 0; i < _count; i++)
        {
            if (node.Value.Equals(item))
            {
                result = i;
                break;
            }
            node = node.NextNode;
        }
        return result;
    }
    //---包含---
    public bool Contains(T item)
    {
        return IndexOf(item) > -1 ? true : false;
    }
    //---删除---
    public void RemoveAt(int index)
    {
        if (index >= 0 && index < _count)
        {
            Node<T> prev = null;
            Node<T> node = head;
            if (index == 0)
            {
                head = head.NextNode;
            }
            else
            {
                for (int i = 0; i < index; i++)
                {
                    prev = node;
                    node = node.NextNode;
                }
                prev.NextNode = node.NextNode;
            }
            _count--;
        }
        else throw new Exception("Out of Range !");
    }
    //---删除---
    public bool Remove(T item)
    {
        int n = IndexOf(item);
        if (n < 0) { return false; }
        RemoveAt(n);
        return true;
    }
    //---索引器---
    public T this[int index]
    {
        get
        {
            if (index >= 0 && index < _count)
            {
                Node<T> node = head;
                for (int i = 0; i < index; i++)
                {
                    node = node.NextNode;
                }
                return node.Value;
            }
            else throw new Exception("Out of Range !");
        }
        set
        {
            Insert(index, value);
        }
    }
    //---只读?---
    public bool IsReadOnly
    {
        get { return false; }
    }
    //---拷贝---
    public void CopyTo(T[] array, int arrayIndex)
    {
        Node<T> node = head;
        for (int i = 0; i < _count; i++)
        {
            array[arrayIndex + i] = node.Value;
            node = node.NextNode;
        }
    }
}
//=====单向链表元素=====
class Node<T>
{
    public T Value;
    public Node<T> NextNode;
    public Node() : this(default(T)) { }
    public Node(T value)
    {
        Value = value;
        NextNode = null;
    }
}

 

Guess you like

Origin www.cnblogs.com/wwwbdabc/p/11653037.html