抄过来的C#顺序表(unsafe)

从这两地方抄的:

线性表(2)——顺序表的动态实现 – 柒氿 (whitedew.work)

C#高性能低GC非托管动态扩容数组 – 知乎 (zhihu.com)

为了操作内存用了unsafe开发,有很多瑕疵和缺点。但我懒得改了,差不多能跑,使用中基本不会出错就行了(反正也不用)。

在unity里测试的,所以输出用了Debug.log系列

public unsafe class Linear<Data> where Data : unmanaged
{
    Data* head;
    readonly int byteSize;  //Data的size
    readonly int baseSize;  //初始容量
    int size;               //当前容量
    public int Length { get; private set; }
}
    public Data this[int index]
    {
        get
        {
            if(!IsInLength(index))
            {
                throw new OverflowException("访问越界!");
            }
            return head[index];
        }
        private set
        {
            EnsureCapacity(ref index);
            head[index] = value;
        }
    }
    //检查容量,若不足再开辟
    void EnsureCapacity(ref int index)
    {
        if (index < size) return;
        while (index >= size)
        {
            size += baseSize;
            GC.AddMemoryPressure(byteSize * baseSize);
        }
        Extend();
    }
    void Extend()
    {
        head = (Data*)Marshal.ReAllocHGlobal((IntPtr)head, new IntPtr(size * byteSize));
    }
    public Linear(int n)
    {
        byteSize = (byte)sizeof(Data);
        head = (Data*)Marshal.AllocCoTaskMem(byteSize * n);
        if (head == null)
        {
            throw new Exception("初始化分配内存出错啦!");
        }
        GC.AddMemoryPressure(byteSize * n);
        size = baseSize = n;
        Length = 0;
    }
    ~Linear()
    {
        //Linear<Data>本身还是托管的
        Destroy();
    }
    private void Destroy()
    {
        if (head != null)
        {
            Marshal.FreeHGlobal((IntPtr)head);
            GC.RemoveMemoryPressure(byteSize * size);
            Length = 0;
            size = 0;
        }
    }
    public void Clear()
    {
        Length = 0;
    }
    public void ListTraverse()
    {
        for (int i = 0; i < Length; i++)
        {
            Debug.Log($"{i}:{head[i]}");
        }
    }
    public bool IsListEmpty() => Length == 0;
    public Data GetElem(int pos)
    {
        IsInLength(pos, () => throw new OverflowException("访问越界!"));
        return head[pos];
    }
    public int? LocateElem(Data e,int start,int end)
    {
        for (int i = start; i < end; i++)
        {
            //无法直接用 == 来判断Data类型实例之间是否相等
            //不清楚Equals和ReferenceEquals是否适用(懒得测试了)
            Hash128 hash1 = new Hash128();
            Hash128 hash2 = new Hash128();
            HashUnsafeUtilities.ComputeHash128(&head[i], (ulong)byteSize, &hash1);
            HashUnsafeUtilities.ComputeHash128(&e, (ulong)byteSize, &hash2);
            if (Equals(hash1, hash2))
            {
                return i;
            }
        }
        return null;
    }
    public int? LocateElem(Data e)
    {
        return LocateElem(e, 0, Length);
    }
    public Data PriorElem(Data cur)
    {
        int? result = LocateElem(cur, 1, Length);
        if(result is null)
        {
            throw new NullReferenceException("fail in PriorElem");
        }
        return head[(int)result-1];
    }
    public Data NextElem(Data cur)
    {
        int? result = LocateElem(cur, 0 ,Length - 1);
        if (result is null)
        {
            throw new NullReferenceException("fail in NextElem");
        }
        return head[(int)result+1];
    }
    private bool IsInLength(int pos, Action action = null)
    {
        if (pos >= 0 && pos < Length)
        {
            return true;
        }
        action.Invoke();
        return false;
    }
    public bool IsInLength(int pos)
    {
        return IsInLength(pos, null);
    }
    public void SetElem(int pos,Data e)
    {
        IsInLength(pos, () => throw new OverflowException("设置越界!"));
        head[pos] = e;
    }
    public bool InsertElem(int pos, Data e)
    {
        if(pos<0||pos>Length)
        {
            Debug.LogWarning("插入越界!");
            return false;
        }
        for (int j = Length - 1; j >= pos; j--)
        {
            head[j + 1] = head[j];//向后拷贝,节约时间
        }
        head[pos] = e;
        ++Length;
        return true;
    }
    public bool DeleteElem(int pos)//删除指定位置上的元素并返回
    {
        if (!IsInLength(pos, () => Debug.LogWarning("删除越界!")))
        {
            return false;
        }
        for (int j = pos + 1; j < Length; j++)
        {
            head[j - 1] = head[j];
        }
        --Length;
        return true;
    }
    void Start()
    {
        Linear<int> li = new Linear<int>(5);
        li.InsertElem(0, 3);
        li.InsertElem(1, 8);
        li.InsertElem(2, 42);
        li.Clear();
        li.InsertElem(0, 7);
        li.InsertElem(1, 5);
        li.InsertElem(2, 4);
        li.InsertElem(3, 12);
        li.InsertElem(4, 91);
        li.ListTraverse();
        Debug.LogError(li.LocateElem(4));
        Debug.LogError(li.NextElem(7));
    }
0:7
1:5
2:4
3:12
4:91
2
5
    void Start()
    {
        Linear<Vector3> li2 = new Linear<Vector3>(5);
        li2.InsertElem(0, Vector3.forward);
        li2.InsertElem(1, Vector3.right);
        li2.InsertElem(2, Vector3.back);
        li2.InsertElem(3, Vector3.down);
        li2.DeleteElem(2);
        li2.ListTraverse();
        Debug.LogError(li2.LocateElem(Vector3.right));
    }
0:(0.00, 0.00, 1.00)
1:(1.00, 0.00, 0.00)
2:(0.00, -1.00, 0.00)
1

差不多就这些了,等柒氿那边更新了我再抄过来。

© 版权声明
THE END
喜欢就点个赞吧
点赞0 分享
评论 共2条

请登录后发表评论