1. 程式人生 > >C#順序表 & 單向鏈表(無頭)

C#順序表 & 單向鏈表(無頭)

student 參數 eric false () 數據添加 nod gef string

C# 順序表

非常標準的順序表結構,等同於C#中的List<T>,但是List<T>在排錯查詢和數據結構替換上存在缺陷,一些情況會考慮使用自己定義的數據結構

1.優化方向 下表使用冒泡排序,可以考慮優化算法


/***************************************
作者: 未聞花語
版本: v1.5
最後修改時間: 2018/05/18
電話: 159****7727
功能&使用方法: 
 * 泛型順序表 [Update]
 * 1.新增了預擴容功能 (新增了一個構造函數 在創建之初設置其容量大小)
 * 2.所有判斷相等的方法都是通過 委托傳入 包括 “排序”及 “判斷是否存在”
 * 3.擴容大小為原大小的1.5倍, 如果覺得不合適 可自行調整 一般為1.5倍
 * 4.增加了插入函數 
 * 5.添加了預擴容的安全校驗
 * 
 * 優點:
 * 1.無需為表示表中對象的關系而增加額外的存儲空間
 * 2.可以快速的獲取表中任一位置的數據
 * 3.C#中的List就是使用的這種存儲形式
 * 
 * 缺點:
 * 1.插入和刪除操作 移動的元素過多 時間開銷大
 * 2.長度增長時對內存開銷較大(現在修改為原數據的大小的1.5倍)
 * ,會存在內存浪費!一般稱為內存碎片。
 * 
 * 適用:
 *    適用於數據長度變化不大 且 索取頻繁的情況
 * 
 * 
 * 存在方法:
 * <0> ----------- MyArrayList<T>() -------- 無參構造
 * <1> ----------- Size() ------------------ 得到使用空間
 * <2> ----------- Expansion()(私有)------ 擴容
 * <3> ----------- Add(T data) ------------- 添加數據
 * <4> ----------- (r)T At(int index) ------ 得到數據
 * <5> ----------- Clear() ----------------- 清空數據
 * <6> ----------- (r)T this[int index] ---- 得到/設置 數據【索引器】
 * <7> ----------- SortSmallToBig() -------- 排序(從小到大)(冒泡排序)
 * <8> ----------- Show(Action<T>) --------- 自定義打印
 * <9> ----------- Contains(T) ------------- bool類型返回是否包含這個東西
 * <10> ---------- Insert(T _data, int _index) 插入
 * <11> ---------- Delete(_index) ---------- 刪除數據
 * 
 * 存在屬性:
 * Capacity ------ 容量
 * Size ---------- 當前使用空間
**************************************
*/ #if UNITY_EDITOR using UnityEngine; #endif using System.Collections; using System; namespace MyList { public class MyArrayList<T> { //容量 int m_capacity; //使用量 int m_size; //堆 --- 指針 T[] obj; //構造0 (無參構造) public MyArrayList() {
//內存容量 (默認為4) m_capacity = 4; //空間使用量歸0 m_size = 0; //開堆 obj = new T[m_capacity]; } //構造1 (帶參構造) public MyArrayList(int _capacity) { //內存容量 m_capacity = _capacity > 1 ? _capacity : 2;
//空間使用量歸0 m_size = 0; //開堆 obj = new T[m_capacity]; } //方法 --- 擴容 void Expansion() { //容量 == 使用量 if (m_size == m_capacity) { ////容量擴大一倍 //m_capacity *= 2; //容量擴大為原來的1.5倍 m_capacity = (int)(m_capacity * 1.5); //數據開堆 T[] nt = new T[m_capacity]; //復制數據 for (int i = 0; i < m_size; ++i) { nt[i] = obj[i]; } //修改數據結構指針指向 obj = nt; } } //方法 --- 數據添加 public void Add(T data) { //擴容 Expansion(); //放入數據 obj[m_size++] = data; } //方法 --- 插入 public void Insert(T _data, int _index) { //容量檢查 Expansion(); //移動數據 for (int i = Size; i > _index; i--) { obj[i] = obj[i - 1]; } //填入數據 obj[_index] = _data; m_size++; } //方法 --- 得到數據[下標索引] public T At(int index) { //參數檢查 if (index < 0 || index >= m_size) return default(T); else return obj[index]; } //方法 --- 清空 public void Clear() { //使用空間修改為0就可以了 m_size = 0; } //索引器a public T this[int index] { set { //設置數據 在 範圍內 if (index >= 0 && index < m_size) { obj[index] = value; } } get { if (index >= 0 && index < m_size) return obj[index]; else return default(T); } } //聲明委托 //case 1 -------------- Left > Right //case 0 -------------- Left == Right //case -1 -------------- Left < Right public delegate int CompareTo(T _objLeft, T _objRight); //方法 --- 排序(冒泡) public void SortSmallToBig(CompareTo CTF) { //冒泡排序 for (int i = 0; i < m_size; ++i) { for (int j = m_size - 1; j > i; --j) { if (CTF(obj[i], obj[j]) > 0) { T temp = obj[i]; obj[i] = obj[j]; obj[j] = temp; } } } } //遍歷顯示(C#控制臺顯示) public void Show(Action<T> _func) { //遍歷 for (int i = 0; i < m_size; ++i) { //這個顯示方式比 _func(obj[i]); } } //遍歷查找 public bool Contains(T t, CompareTo CTF) { //遍歷 for (int i = 0; i < m_size; ++i) { if (CTF(t, obj[i]) == 0) { return true; } } //否則return false return false; } //屬性 ----- 返回容量 public int Capacity { get { return m_capacity; } } //屬性 ----- 返回使用空間 public int Size { get { return m_size; } } //刪除數據 public void Delete(int _index) { if (_index < 0 || _index > m_size - 1) return; for (int i = _index; i < m_size; ++i) obj[i - 1] = obj[i]; m_size--; } } }

C# 鏈表(單向無頭)

單向非閉環,無表頭的鏈表,一般用於非隊尾數據需要進行頻繁刪減的情況,由於沒有表頭所有排序算法寫的有點low

技術分享圖片

1.優化方向,改成雙向鏈表,但是改成雙向鏈表會花點時間因為指針的操作比較多,很容易出現閉環的情況如下圖

技術分享圖片


/***************************************
作者: 未聞花語
版本: v1.1
最後修改時間: 2018/05/20
電話: 159****7727
功能&使用方法: 
 * 泛型單向鏈表 [Update]
 * 修改了Show函數的一個bug
 * 沒有表頭!!
 * 
 * 優點:
 * 1.自然是插入和排序時,速度較快
 * 2.當元素數目區間不確定時,不會有較大空間的浪費
 * 
 * 缺點:
 * 1.平凡的內存申請與銷毀(可通過 修改成帶緩存的鏈表或使用對象池來解決)
 * 2.相較於順序表 略微增加了內存開銷
 * 3.相較於順序表 下標查詢略微緩慢
 * 
 * 適用:
 *    適用於數據長度不確定,又存在平凡刪減的情況
 * 
 * 
 * 存在方法:
 * <0> ----------- Add(T data) ------------- 添加數據
 * <1> ----------- (r)T At(int index) ------ 得到數據[索引器]
 * <2> ----------- Delete(_index) ---------- 刪除數據
 * <3> ----------- Inset(T _data, int _index) 插入數據
 * <4> ----------- Clear() ----------------- 清空數據
 * 
 * 存在屬性:
 * Capacity ------ 容量
 * Size ---------- 當前使用空間
***************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyList
{
    class Node<T>
    {
        private T m_data;
        public T Data { get { return m_data; } set { m_data = value; } }
        private Node<T> m_next;
        public Node<T> Next { get { return m_next; } set { m_next = value; } }
        public Node(T _data)
        {
            Data = _data;
            this.Next = default(Node<T>);
        }
    }
    class MyLinkList<T>
    {
        //表頭
        Node<T> m_head;
        //表長
        private int m_size;
        public int Size { get { return m_size; } }
        //構造
        public MyLinkList()
        {
            m_size = 0;
            m_head = null;
        }
        //添加數據 
        public void Add(T _data)
        {
            Node<T> nNote = new Node<T>(_data);
            if (Size == 0)
            {
                m_head = nNote;
            }
            else
            {
                Node<T> p = m_head;
                while (p.Next != null)
                {
                    p = p.Next;
                }
                p.Next = nNote;
            }
            m_size++;
        }
        //刪除數據
        public bool Delete(int _index)
        {
            if (_index < 0 || _index > Size - 1)
                return false;
            Node<T> preP = m_head;
            Node<T> afterP = m_head;
            for (int i = 0; i < _index - 1; ++i)
                preP = preP.Next;
            if (_index == Size - 1)
                afterP = null;
            else
            {
                for (int i = 0; i < _index + 1; ++i)
                    afterP = afterP.Next;
            }
            preP.Next = afterP;
            m_size--;
            return true;
        }
        //插入數據
        public bool Insert(T _data, int _index)
        {
            if (_index < 0 || _index > Size - 1)
                return false;
            Node<T> nNote = new Node<T>(_data);
            if (_index == 0)
            {
                nNote.Next = m_head;
                m_head = nNote;
                m_size++;
                return true;
            }
            Node<T> preP = m_head;
            for (int i = 0; i < _index - 1; ++i)
                preP = preP.Next;
            nNote.Next = preP.Next;
            preP.Next = nNote;
            m_size++;
            return true;
        }
        //得到數據
        public T At(int _index)
        {
            T r = default(T);
            if (_index < 0 || _index > Size - 1)
                return r;
            Node<T> P = m_head;
            for (int i = 0; i < _index; ++i)
                P = P.Next;
            r = P.Data;
            return r;
        }
        //索引器a
        public T this[int _index]
        {
            set
            {
                //設置數據 在 範圍內
                if (_index >= 0 && _index < m_size)
                {
                    Node<T> P = m_head;
                    for (int i = 0; i < _index; ++i)
                        P = P.Next;
                    P.Data = value;
                }
            }
            get
            {
                if (_index >= 0 && _index < m_size)
                {
                    Node<T> P = m_head;
                    for (int i = 0; i < _index; ++i)
                        P = P.Next;
                    return P.Data;
                }
                else
                    return default(T);
            }
        }
        //清除數據
        public void Clear()
        {
            if (m_size < 1)
                return;
            Node<T> A = m_head;
            Node<T> B = A;
            do
            {
                B = B.Next;
                A.Next = null;
                A = B;
            } while ((B == null));
            m_size = 0;
        }
        //聲明委托 
        //case 1  -------------- Left >  Right  
        //case 0  -------------- Left == Right
        //case -1  -------------- Left <  Right
        public delegate int CompareTo(T _objLeft, T _objRight);
        //判斷存在 CompareTo CTF
        public bool Contains(T _data, CompareTo CTF)
        {
            Node<T> A = m_head;
            while (A != null)
            {
                if (CTF(A.Data, _data) == 0)
                    return true;
                A = A.Next;
            }
            return false;
        }
        //遍歷顯示
        public void Show(Action<T> _func)
        {
            if (m_size == 0)
                return;
            //遍歷 
            Node<T> A = m_head;
            while (A != null)
            {
                //這個顯示方式比
                _func(A.Data);
                A = A.Next;
            }
        }
        //方法 --- 排序(冒泡)
        public void SortSmallToBig(CompareTo CTF)
        {
            //安全校驗
            if (Size < 2)
                return;
            Node<T> A = m_head;
            Node<T> B = m_head;
            //冒泡排序
            for (int i = 0; i < m_size; ++i)
            {
                A = m_head;
                B = A;
                for (int j = m_size - 1; j > i; --j)
                {
                    if (CTF(A.Next.Data, A.Data) < 0)
                    {
                        if (m_head == A)
                        {
                            m_head = A.Next;
                            A.Next = A.Next.Next;
                            m_head.Next = A;
                            B = m_head;
                        }
                        else
                        {
                            B.Next = A.Next;
                            A.Next = B.Next.Next;
                            B.Next.Next = A;
                            B = B.Next;
                        }
                    }
                    else
                    {
                        if (m_head != A)
                        {
                            B = B.Next;
                        }
                        A = A.Next;


                    }
                }
            }
        }
    }
}

測試運行程序

用於測試上述表的運行程序 & 結果

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//包含命名空間 MyList
using MyList;
namespace DataStructure
{
    class Program
    {
        static void Main(string[] args)
        {
            //隨機名字的數組
            string[] rNameSpace = new string[] {"蔣偉","吳悅","曾真","劉蕓",
            "珠海妮","李小滿","薛涵","邱伊雨","李晶晶","戴林江","代安東","黃挺",
                "陳政","葉小青","徐逸"};
            //隨機用戶數
            //(PS:測試用,沒寫限制 所以不要太大 最好不要超過10個)
            const int studentCount = 5;
            //開堆
            //var team0 = new MyArrayList<Student>(3);
            var team0 = new MyLinkList<Student>();
            Student[] students = new Student[studentCount];
            //隨機出現數據 並添加 當隨機種子一樣是數據一樣
            Random ra = new Random(6);
            for (int i = 0; i < studentCount;)
            {
                int id = ra.Next(1, 30);
                string name = rNameSpace[ra.Next(0, rNameSpace.Length)];
                bool isGirl = ra.Next(0, 2) == 0 ? false : true;
                Student s0 = new Student(id, name, isGirl);
                //查找是否有相同的屬性
                if (team0.Contains(s0, StudentJudgeFunc0))
                {
                    continue;
                }
                else
                {
                    team0.Add(s0);
                    ++i;
                }
            }
            //遍歷顯示 & 屬性調用
            Console.WriteLine(""); Console.WriteLine("==================== 分割線 ===================="); Console.WriteLine("");
            team0.Show(ShowFunc);
            Console.WriteLine();
            //Console.WriteLine(string.Format("當前順序表 \t--- \t容量 :\t\t{0}", team0.Capacity));
            Console.WriteLine(string.Format("當前XX表 \t--- \t大小 :\t\t{0}", team0.Size));
            Console.WriteLine(string.Format("下表索引器測試 \t--- \t下標3姓名 :\t{0}", team0[3].m_name));
            Console.WriteLine(""); Console.WriteLine("==================== 排序後 ===================="); Console.WriteLine("");
            team0.SortSmallToBig(StudentJudgeFunc0);
            team0.Show(ShowFunc);
            Console.WriteLine(""); Console.WriteLine("==================== 插入&刪除測試 ===================="); Console.WriteLine("");
            team0.Insert(new Student(16, rNameSpace[1], true), 2);
            team0.Delete(1);
            team0.Show(ShowFunc);
            Console.WriteLine(""); Console.WriteLine("==================== 清空測試 ===================="); Console.WriteLine("");
            team0.Clear();
            team0.Show(ShowFunc);
        }
        //比較函數
        static int StudentJudgeFunc0(Student s0, Student s1)
        {
            if (s0.m_id == s1.m_id || s0.m_name.Equals(s1.m_name))
                return 0;
            if (s0.m_id > s1.m_id)
                return 1;
            else
                return -1;
        }
        //顯示函數
        static void ShowFunc(Student _stu)
        {
            Console.WriteLine(string.Format("{1}\t[{0}]\t ---- \t{2}", _stu.m_id, _stu.m_name, _stu.m_isGirl ? "Gril" : "Boy"));
        }
    }
    class Student
    {
        //學號
        public int m_id;
        //姓名
        public string m_name;
        //性別
        public bool m_isGirl;
        //構造
        public Student(int _id, string _name, bool _isGirl)
        {
            m_id = _id;
            m_name = _name;
            m_isGirl = _isGirl;
        }
    }
}

技術分享圖片

C#順序表 & 單向鏈表(無頭)