C#順序表 & 單向鏈表(無頭)
阿新 • • 發佈:2018-05-21
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#順序表 & 單向鏈表(無頭)