数据结构学习之线性表(二)

开篇:上次我们讲到,实现基本的数组的增删改查。现在我们来优化和改善,并且分析一下。

1. 首先我们定义的数组类型 不支持泛型。

2. 当容量不够使用的时候, 应该可以自动触发扩容操作。

我们来实现一下。我们使用泛型的T类型来代表。

public class Array<T>
    {
        private T[] Data;
        private int Size;
        private int Capacity;
        public bool IsFull => this.Capacity == this.Size;
        public Array(int capacity = 20)
        {
            this.Capacity = capacity;
            this.Data = new T[this.Capacity];
        }
}

此时 增删改查都应该操作泛型T变量

比如 add ,此时我们增加扩容操作,我们来新增个数组 遍历复制操作,容量的大小应该视数组的容量大小来定。

public void Add(T value)
        {
            if (IsFull)
                this.ExpandCapacity(this.Capacity * 2);
            this.Size++;
            this.Data[this.Size - 1] = value;
        }
}
private void ExpandCapacity(int capacity)
 {
        var newData = new T[capacity];
        for (int i = 0; i < newData.Length; i++)
        {
            newData[i] = this.Data[i];
        }
        this.Data = newData;
        this.Capacity = capacity;
 }

删除操作

public T Delete(int index)
{
        if (index < 0)
            throw new Exception("index is less than zero");
        if (index > this.Capacity-1)
            throw new Exception("index is more than capacity");
        if (index > this.Size-1)
            return default;
        var value = this.Data[index];
        for (int i = index; i < this.Size-1; i++)
        {
            this.Data[i] = this.Data[i+1];
        }
        this.SetEmpty(this.Size-1);
        this.Size--;
        if (this.Size <= this.Capacity/2)
           this.NarrowCapacity(this.Capacity / 2);
        return value;
 }

private void NarrowCapacity(int capacity)
{
        var newData = new T[capacity];
        for (int i = 0; i < this.Data.Length; i++)
        {
            newData[i] = this.Data[i];
        }
         this.Data = newData;
         this.Capacity = capacity;
}

 

此时查找等需要比较的操作 需要 T类型去重写 object基类的Equals()规则

public bool IsContain(int value)
{
        var isContain = false;
        for (int i = 0; i < this.Size; i++)
        {
            if (this.Data[i].Equals(value))
                isContain = true;
        }
        return isContain;
}

 

此时我们来看我们的算法的复杂度

1.增加 O(1) 这个没什么好说 ,但如果已满,触发了扩容复杂度为 O(n)。

2.插入  插入的话,如果插入的index为Size ,此时的复杂度为 O(1) ,但最坏情况下为插入到第一个,此时的复杂度为 O(n),平均复杂度为(n/2),还是 O(n)

3.删除 删除也是一样。也会有最坏情况,复杂度为 O(n).

4.查找 O(1) 

 

但是有个问题,比如,此时的容量已满我们增加了一个,触发扩容,此时又删除最后一个,此时的数组的Size为容量的一半,又要缩容器。都是O(1)的操作,此时的复杂度就会是O(n),(复杂度震荡),此时我们可以改一下。当size小于容器的1/4,才触发缩容器。避免了这种又增又删O(1)一次的操作带来的复杂度震荡。

if (this.Size <= this.Capacity/4)
               this.NarrowCapacity(this.Capacity / 2);

如下我的项目的 Github地址  有需要的同学可以自取哦 地址: https://github.com/GuanZhengXin/DataStruct

这样我们就简单实现了一个基本的数组结构,下期我们来学习一下栈的结构和实现。

posted @ 2019-06-16 22:35  MUYIgUAN  阅读(145)  评论(0编辑  收藏