数组和链表

数组

  1. 数组内存分配在连续的内存区域上。
  2. 数组需要预申请大小,可能造成内存浪费。
  3. 随机读取效率高,因为数组内存是连续的,知道每一个数据的地址,可以直接找到指定索引数据。
  4. 增删效率低,需要移动受影响的数据的位置。
  5. 由于内存区域连续,有CPU缓存命中高的优势,访问效率高。

链表

  1. 链表可分配在内存任意地方,不要求连续。
  2. 无需预指定大小,可自由调整数据量。
  3. 不支持随机读取,查询数据较慢,需要从头开始遍历查找。
  4. 增删速度快,只需要修改指针指向即可。
  5. 由于内存分散,往往前后节点数据不能同时处于缓存中,访问效率低。

时间复杂度

-数组链表
读取O(1)O(n)
插入O(n)O(1)
删除O(n)O(1)
时间复杂度

动态数组

根据元素个数动态调整数组大小

实现

public class List<T>
{
    private T[] array;
    private int count;

    public int Count => count;

    public int Capacity => array.Length;

    private static T[] emptyArray = new T[0];

    public List()
    {
        array = emptyArray;
        count = 0;
    }

    public List(int capacity)
    {
        array = new T[capacity];
        count = 0;
    }

    public void Set(int index, T value)
    {
        if (count == Capacity)
            Resize((Capacity == 0) ? 4 : Capacity * 2);//容量从4起步,每次扩容翻倍

        array[index] = value;
        count++;
    }

    public T Get(int index)
    {
        if (index > count - 1)
        {
            throw new Exception("List out of range");
        }

        return array[index];
    }

    public void RemoveAt(int index)
    {
        for (int i = index; i < count ; i++)
        {
            array[i] = array[i + 1];        
        }

        count--;

        //若实际数据小于当前容量的1/4,容量缩小至原本的1/2
        if (count > 0 && count <= Capacity / 4)
        {
            Resize(Capacity / 2);
        }
    }

    //调整内部数组大小,新开辟数组,并把旧数组内容拷贝至新数组
    private void Resize(int count)
    {
        T[] _array = new T[count];
        Array.Copy(array, 0, _array, 0, this.count);
        array = _array;
    }
}

单链表

实现

public class ListNode<T> where T : IComparable<T>
{
    public ListNode<T> next;
    public T value;

    public ListNode(T value)
    {
        this.value = value;
    }

    public ListNode(ListNode<T> next, T value)
    {
        this.next = next;
        this.value = value;
    }
}

class LinkedList<T> where T : IComparable<T>
{
    private ListNode<T> head;
    private int count;
    public int Count => count;

    public ListNode<T> First => head.next;


    public LinkedList()
    {
        head = new ListNode<T>(default(T));
    }

    public void AddFirst(T value)
    {
        AddFirst(new ListNode<T>(value));
    }

    public void AddFirst(ListNode<T> node)
    {
        if (node == null)
            return;

        AddNode(head, node);
    }

    public void AddLast(T value)
    {
        AddLast(new ListNode<T>(value));
    }

    public void AddLast(ListNode<T> node)
    {
        if (node == null)
            return;

        ListNode<T> last = head;
        while (last.next != null)
        {
            last = last.next;
        }

        AddNode(last, node);
    }

    public void AddBefore(ListNode<T> node, T value)
    {
        if (node == null)
            return;

        AddBefore(node, new ListNode<T>(value));
    }

    public void AddBefore(ListNode<T> node, ListNode<T> value)
    {
        if (node == null || value == null)
            return;

        ListNode<T> pre = head;
        ListNode<T> addNode = First;
        while (addNode != null && addNode != node)
        {
            pre = pre.next;
            addNode = addNode.next;
        }

        if (addNode == null || addNode.value.CompareTo(node.value) != 0)
            return;

        AddNode(pre, value);
    }

    public void AddAfter(ListNode<T> node, T value)
    {
        if (node == null)
            return;

        AddAfter(node, new ListNode<T>(value));
    }

    public void AddAfter(ListNode<T> node, ListNode<T> value)
    {
        if (node == null || value == null)
            return;

        ListNode<T> addNode = First;
        while (addNode != null && addNode != node)
        {
            addNode = addNode.next;
        }

        if (addNode == null || addNode.value.CompareTo(node.value) != 0)
            return;

        AddNode(node, value);
    }

    public void DeleteNode(T value)
    {
        ListNode<T> pre = head;
        ListNode<T> deleteNode = First;
        while (deleteNode != null && deleteNode.value.CompareTo(value) != 0)
        {
            pre = pre.next;
            deleteNode = deleteNode.next;
        }

        if (deleteNode == null)
            return;

        DeleteNode(pre, deleteNode);
    }

    public void DeleteNode(ListNode<T> node)
    {
        if (node == null)
            return;

        ListNode<T> pre = head;
        ListNode<T> deleteNode = First;
        while (deleteNode != null && deleteNode != node)
        {
            pre = pre.next;
            deleteNode = deleteNode.next;
        }

        if (deleteNode == null)
            return;

        DeleteNode(pre, deleteNode);
    }

    private void DeleteNode(ListNode<T> pre, ListNode<T> deleteNode)
    {
        if (pre == null || deleteNode == null)
            return;

        ListNode<T> next = deleteNode.next;
        pre.next = next;
        count--;
    }

    public ListNode<T> Find(T value)
    {
        ListNode<T> node = First;
        while (node != null && node.value.CompareTo(value) != 0)
        {
            node = node.next;
        }

        return node;
    }

    private void AddNode(ListNode<T> pre, ListNode<T> node)
    {
        if (pre == null || node == null)
            return;

        ListNode<T> next = pre.next;
        pre.next = node;
        node.next = next;
        count++;
    }

    public void Clear()
    {
        head.next = null;
        count = 0;
    }
}

双链表

实现

public class ListNode<T> where T : IComparable<T>
{
    public ListNode<T> pre;
    public ListNode<T> next;
    public T value;

    public ListNode(T value)
    {
        this.value = value;
    }

    public ListNode(ListNode<T> pre, ListNode<T> next, T value)
    {
        this.pre = pre;
        this.next = next;
        this.value = value;
    }
}

class LinkedList<T> where T : IComparable<T>
{
    private ListNode<T> head;
    private ListNode<T> tail;
    private int count;
    public int Count => count;

    public ListNode<T> First
    {
        get
        {
            if (count > 0)
                return head.next;
            else
                return null;
        }
    }

    public ListNode<T> Last
    {
        get
        {
            if (count > 0)
                return tail.pre;
            else
                return null;
        }
    }


    public LinkedList()
    {
        head = new ListNode<T>(default(T));
        tail = new ListNode<T>(default(T));
        head.next = tail;
        tail.pre = head;
    }

    public void AddFirst(T value)
    {
        AddFirst(new ListNode<T>(value));
    }

    public void AddFirst(ListNode<T> node)
    {
        if (node == null)
            return;

        ListNode<T> next = First;
        head.next = node;
        node.next = next;
        if (next != null) next.pre = node;
        count++;
    }

    public void AddLast(T value)
    {
        AddLast(new ListNode<T>(value));
    }

    public void AddLast(ListNode<T> node)
    {
        if (node == null)
            return;

        node.pre = tail.pre;
        tail.pre.next = node;
        tail.pre = node;

        count++;
    }

    public void AddBefore(ListNode<T> node, T value)
    {
        if (node == null)
            return;

        AddBefore(node, new ListNode<T>(value));
    }

    public void AddBefore(ListNode<T> node, ListNode<T> value)
    {
        if (node == null || value == null)
            return;

        ListNode<T> pre = head;
        ListNode<T> addNode = First;
        while (addNode != null && addNode != node)
        {
            pre = pre.next;
            addNode = addNode.next;
        }

        if (addNode == null)
            return;

        pre.next = value;
        if (pre != head) value.pre = pre;
        value.next = node;
        node.pre = value;

        count++;
    }

    public void AddAfter(ListNode<T> node, T value)
    {
        if (node == null)
            return;

        AddAfter(node, new ListNode<T>(value));
    }

    public void AddAfter(ListNode<T> node, ListNode<T> value)
    {
        if (node == null || value == null)
            return;

        ListNode<T> addNode = First;
        while (addNode != null && addNode != node)
        {
            addNode = addNode.next;
        }

        if (addNode == null)
            return;

        ListNode<T> next = node.next;
        node.next = value;
        value.pre = node;
        value.next = next;
        if (next == null) tail.pre = value;

        count++;
    }

    public void DeleteNode(T value)
    {
        ListNode<T> pre = head;
        ListNode<T> deleteNode = First;
        while (deleteNode != null && deleteNode.value.CompareTo(value) != 0)
        {
            pre = pre.next;
            deleteNode = deleteNode.next;
        }

        if (deleteNode == null)
            return;

        DeleteNode(pre, deleteNode);
    }

    public void DeleteNode(ListNode<T> node)
    {
        if (node == null)
            return;

        ListNode<T> pre = head;
        ListNode<T> deleteNode = First;
        while (deleteNode != null && deleteNode != node)
        {
            pre = pre.next;
            deleteNode = deleteNode.next;
        }

        if (deleteNode == null)
            return;

        DeleteNode(pre, deleteNode);
    }

    private void DeleteNode(ListNode<T> pre, ListNode<T> deleteNode)
    {
        if (pre == null || deleteNode == null)
            return;

        ListNode<T> next = deleteNode.next;
        pre.next = next;
        if (pre != head) next.pre = pre;

        count--;
    }

    public ListNode<T> Find(T value)
    {
        ListNode<T> node = First;
        while (node != null && node.value.CompareTo(value) != 0)
        {
            node = node.next;
        }

        return node;
    }

    public void Clear()
    {
        head.next = tail;
        tail.pre = head;
        count = 0;
    }
}

先进后出

应用

  1. 基于栈实现的UI框架
  2. 编辑器中撤回和重做的操作
  3. 括号合法检查
  4. 基于栈实现简单的表达式计算

数组实现

public class Stack<T>
{
    private T[] array;
    private int count;

    public int Count => count;

    private static T[] emptyArray = new T[0];

    public Stack()
    {
        array = emptyArray;
        count = 0;
    }

    public Stack(int capacity)
    {
        array = new T[capacity];
        count = 0;
    }

    public bool IsEmpty()
    {
        return count <= 0;
    }

    public T Peek()
    {
        if (count == 0)
        {
            throw new Exception("Stack count is 0.");
        }
        else
        {
            return array[count - 1];
        }
    }

    public void Push(T t)
    {
        if (count == array.Length)
        {
            Resize((array.Length == 0) ? 4 : (2 * array.Length));
        }

        array[count++] = t;
    }

    public T Pop()
    {
        if (count == 0)
        {
            throw new Exception("Stack count is 0.");
        }

        T t = array[--count];
        array[count] = default(T);

        if (count > 0 && count == array.Length / 4)
        {
            Resize(array.Length / 2);
        }

        return t;
    }

    private void Resize(int count)
    {
        T[] _array = new T[count];
        Array.Copy(array, 0, _array, 0, this.count);
        array = _array;
    }
}

链表实现

public class Stack<T>
{
    private class ListNode<Y>
    {
        public ListNode<Y> next;
        public Y value;

        public ListNode(Y value)
        {
            this.value = value;
        }

        public ListNode(ListNode<Y> node, Y value)
        {
            this.next = node;
            this.value = value;
        }
    }

    private ListNode<T> first;
    private int count;

    public int Count => count;

    public bool IsEmpty()
    {
        return first == null;
    }

    public T Peek()
    {
        if (first == null)
        {
            throw new Exception("Stack count is 0.");
        }
        else
        {
            return first.value;
        }
    }

    public void Push(T value)
    {
        ListNode<T> oldFirst = first;
        first = new ListNode<T>(value);
        first.next = oldFirst;

        count++;
    }

    public T Pop()
    {
        if (count == 0)
        {
            throw new Exception("Stack count is 0.");
        }

        T value = first.value;
        first = first.next;

        count--;

        return value;
    }
}

队列

先进先出

应用

  1. 消息队列,降低峰值
  2. 动画队列,按顺序逐个播放动画
  3. BFS
  4. 排队问题等

数组实现

public class Queue<T>
{
    private int front;
    private int rear;
    private T[] array;

    private static T[] emptyArray = new T[4];

    public int Capacity => array.Length;
    public int Count => (rear + Capacity - front) % Capacity;
    public bool IsEmpty => front == rear;
    private bool IsFull => (rear + 1) % Capacity == front;

    public Queue()
    {
        array = emptyArray;
        front = 0;
        rear = 0;
    }

    public Queue(int capacity)
    {
        array = new T[capacity];
        front = 0;
        rear = 0;
    }

    public void Enqueue(T value)
    {
        if (IsFull)
        {
            Resize(Capacity * 2);
        }

        array[rear] = value;
        rear = (rear + 1) % Capacity;
    }

    public T Dequeue()
    {
        if (IsEmpty)
        {
            throw new Exception(("Queue count is 0."));
        }

        T value = array[front];
        array[front] = default(T);
        front = (front + 1) % Capacity;

        if (Count > 0 && Count == Capacity / 4)
        {
            Resize(Capacity / 2);
        }

        return value;
    }

    public T Peek()
    {
        if (IsEmpty)
        {
            throw new Exception("Queue count is 0.");
        }

        return array[front];
    }

    private void Resize(int size)
    {
        T[] newArray = new T[size];

        int index = front;
        int newIndex = 0;
        while (newIndex < Count)
        {
            newArray[newIndex++] = array[index];
            index = (index + 1) % Capacity;
        }
        front = 0;
        rear = newIndex;
        array = newArray;
    }
}

链表实现

public class Queue<T>
{
    private class Node<Y>
    {
        public Node<Y> next;
        public Y value;

        public Node(Y value)
        {
            this.value = value;
        }

        public Node(Node<Y> node, Y value)
        {
            this.next = node;
            this.value = value;
        }
    }

    private Node<T> first;
    private Node<T> last;
    private int count;

    public int Count => count;
    public bool IsEmpty => first == null;

    public void Enqueue(T value)
    {

        Node<T> oldLast = last;
        last = new Node<T>(value);
        if (IsEmpty)
        {
            first = last;
        }
        else
        {
            oldLast.next = last;
        }

        count++;
    }

    public T Dequeue()
    {
        if (IsEmpty)
        {
            throw new Exception("Queue count is 0.");
        }

        T value = first.value;
        first = first.next;

        if (IsEmpty)
            last = null;

        count--;
        return value;
    }

    public T Peek()
    {
        if (IsEmpty)
        {
            throw new Exception("Queue count is 0.");
        }

        return first.value;
    }
}

双端队列

双端队列同时具有栈的先进后出特性,也具有队列的先进先出特性。

应用

  1. KTV式可插歌的点歌系统
  2. LRU

游戏开发者(萌新