資料結構複習---順序表和單鏈表
1.前言:
最近比較浮躁,想學習一門新的技術卻總是淺嘗輒止,遇到不懂的地方就想跳過去,時間長了,心態就有點崩了。靜下心來,去喝了幾碗心靈雞湯。雞湯博主感動到了我:"無專注,無風景。不要太貪心,一次只做一件事,而且只做最重要的事。".於是乎,我把家裡翻了個底朝天,找到了我墊在床底下的《資料結構》這本書,覺得自己是時候靜下心來好好複習一下基礎了。今天剛看到順序表和連結串列,把我的學習心得記錄在這裡。也希望自己能堅持,老老實實的把這本書複習完。
2.資料結構的重要性:
講一門知識之前,通常流程都是要是先吹一波這個東西的重要性,資料結構和演算法雖然已經被吹上天了,我還是覺得有必要:眾所周知,資料結構是計算機專業中最重要的課程之一,可是為什麼呢?用處太多難以列舉,總結成一句話就是:可以讓你的程式跑更快
3.順序表:
順序表是最簡單,最常用,最基本的資料結構
特點:1.結構中的元素存在1對1的線性關係,這種1對1的關係指的是資料元素之間的關係
2.位置有先後關係,除第一個位置的元素外,其他位置的元素前面都只有一個數據元素,相反除最後一個位置的資料元素外,其他位置的資料元素後面都只有一個元素。
CLR中的實現:List<T>
順序表儲存結構:
c#實現順序表(程式碼中只實現了順序表的基本功能,沒有去做健壯性處理):
/// <summary> ///View Code順序表 /// </summary> /// <typeparam name="T"></typeparam> public class ListDS<T> : IListDS<T> { #region 初始化--2019年1月6日23:20:11 /// <summary> ///儲存資料 /// </summary> private T[] Data; /// <summary> /// 表示儲存了多少資料/// </summary> private int Count; /// <summary> /// 建構函式 /// </summary> /// <param name="size">資料大小</param> public ListDS(int size) { Data = new T[size]; Count = 0; } public ListDS() : this(10) { } #endregion #region 索引器--2019年1月6日23:20:06 /// <summary> /// 索引器 /// </summary> /// <param name="index"></param> /// <returns></returns> public T this[int index] => GetEle(index); #endregion #region 新增--2019年1月6日23:20:03 /// <summary> /// 新增方法 /// </summary> /// <param name="item">新增的元素</param> public void Add(T item) { if (Count == Data.Length) { Console.WriteLine("當前順序表已存滿"); return; } Data[Count] = item; Count++; } #endregion #region 清空--2019年1月6日23:19:58 /// <summary> /// 清空 /// </summary> public void Clear() { Count = 0; } #endregion #region 插入資料--2019年1月6日23:19:54 /// <summary> /// 插入資料 陣列向後移動 /// </summary> /// <param name="item"></param> /// <param name="index"></param> public void Insert(T item, int index) { for (int i = Count - 1; i >= index; i--) { Data[i + 1] = Data[i]; } Data[index] = item; Count++; } #endregion #region 刪除--2019年1月6日23:19:51 /// <summary> /// 刪除 刪除資料後 陣列從後往前移動 /// </summary> /// <param name="index"></param> /// <returns></returns> public T Delete(int index) { T temp = Data[index]; for (int i =index+1 ; i < Count; i++) { Data[i - 1] = Data[i]; } Count--; return temp; } #endregion #region 根據索引獲取順序表元素--2019年1月6日23:19:46 /// <summary> /// 根據索引獲取順序表元素 /// </summary> /// <param name="index"></param> /// <returns></returns> public T GetEle(int index) { //判斷元素是否存在 if (index >= 0 && index <= Count - 1) { return Data[index]; } return default(T); } #endregion #region 獲取陣列長度--2019年1月6日23:19:43 /// <summary> /// 獲取陣列長度 /// </summary> /// <returns></returns> public int GetLength() { return Count; } #endregion #region 是否為空--2019年1月6日23:19:40 /// <summary> /// 是否為空 /// </summary> /// <returns></returns> public bool IsEmpty() { return Count == 0; } #endregion #region 根據元素獲取索引--2019年1月6日23:19:36 /// <summary> /// 根據元素獲取索引 /// </summary> /// <param name="value"></param> /// <returns></returns> public int Locate(T value) { for (int i = 0; i < Count-1; i++) { if (Data[i].Equals(value)) { return i; } } return -1; } #endregion }
4.連結串列
順序表使用地址連續的儲存單元順序儲存線性表中的各個資料元素,邏輯上想來的資料元素在物理位置上也相鄰,因此,在順序表中查詢任何一個位置上的資料元素非常方便,這是順序表的有點,BUT,順序表插入/刪除時,需要通過移動資料元素,影響了執行效率,線性表的另外一種儲存結構--鏈式儲存(Linkend Storage)這樣的線性表叫連結串列。因此,對連結串列進行插入和刪除時,不需要移動資料元素,但同時也失去了順序表可隨機儲存的優點
CLR中的實現:LinkedList<T>
鏈式儲存結構:
c#實現單鏈表節點:
/// <summary> /// 單鏈表節點 /// </summary> class Node<T> { #region 初始化 public T data;//儲存資料 public Node<T> next;//指標 指向下一個元素 public Node(T _data) { this.data = _data; next = null; } public Node(T _data,Node<T> _node) { this.data = _data; next = _node; } public Node() { this.data = default(T); this.next = null; } public T Data { get { return data; } set { data = value; } } public Node<T> Next { get { return next; } set { next = value; } } #endregion }View Code
c#實現單鏈表:
/// <summary> /// 單鏈表 /// </summary> /// <typeparam name="T"></typeparam> public class LinkList<T> : IListDS<T> { #region 初始化 /// <summary> /// 頭節點 /// </summary> private Node<T> _head; public LinkList() { _head = null; } #endregion #region 索引器 /// <summary> /// 索引器 /// </summary> /// <param name="index"></param> /// <returns></returns> public T this[int index] => GetEle(index); #endregion #region 新增 /// <summary> /// 新增 /// </summary> /// <param name="item"></param> public void Add(T item) { //1. 建立一個新節點 //2. 如果頭節點為空,賦值給頭節點 return //3.1 如果頭節點不為空 //3.2 建立一個節點指向頭節點 //3.3 迴圈找到尾節點 //3.4 新節點放在尾部 Node<T> newNode = new Node<T>(item); if (_head == null) { _head = newNode; return; } Node<T> temp = _head; while (true) { if (temp.Next != null) { temp = temp.Next; } else { break; } } temp.Next = newNode; } #endregion #region 清空 /// <summary> /// 清空 /// </summary> public void Clear() { //清空頭節點,垃圾回收器自動回收所有未引用的物件 _head = null; } #endregion #region 刪除 /// <summary> /// 刪除 /// </summary> /// <param name="index"></param> /// <returns></returns> public T Delete(int index) { //1.如果是頭節點,講指標指向下一個元素 //2.如果不是頭節點,找到要刪除節點的前一個節點和要刪除的節點 //3.將引用指向要刪除的節點的後一個節點 T data = default(T); //刪除頭節點 if (index == 0) { data = _head.Data; _head = _head.Next; return data; } Node<T> temp =_head; for (int i = 1; i < index - 1; i++) { temp = temp.Next; } Node<T> preNode = temp;//要刪除的節點的前一個節點 Node<T> currentNode = temp.Next;//要刪除的節點 data = currentNode.Data; Node<T> nextNode = temp.Next.Next; preNode.Next = nextNode; return data; } #endregion #region 根據索引訪問 /// <summary> /// 根據索引訪問 /// </summary> /// <param name="index"></param> /// <returns></returns> public T GetEle(int index) { Node<T> temp = _head; for (int i = 1; i <=index; i++) { temp = temp.Next; } return temp.Data; } #endregion #region 獲取長度 /// <summary> /// 獲取長度 /// </summary> /// <returns></returns> public int GetLength() { if (_head == null) { return 0; } int count = 1; Node<T> temp = _head; while (true) { if (temp.Next != null) { count++; temp = temp.Next; } else { break; } } return count; } #endregion #region 插入 /// <summary> /// 插入 /// </summary> /// <param name="item">資料</param> /// <param name="index">位置</param> public void Insert(T item, int index) { //1. 建立一個新節點 //2. 如果索引為0(頭節點) 賦值給頭節點 return //3.1 如果不是頭節點,找到要插入的節點的前一個節點和要插入的節點 //3.2 前一個節點指向新節點 //3.3 新節點指向前一個節點 Node<T> newNode = new Node<T>(item); if (index== 0) { newNode.Next = _head; _head = newNode; return; } Node<T> temp = new Node<T>(); for (int i = 1; i < index-1; i++) { temp = temp.Next; } Node<T> preNode = temp;//要插入的節點的前一個節點 Node<T> curentNode = temp.Next;//要插入的節點 preNode.next = newNode; newNode.Next = curentNode; } #endregion #region 清空 /// <summary> /// 清空 /// </summary> /// <returns></returns> public bool IsEmpty() { return _head == null; } #endregion #region 根據資料訪問索引 /// <summary> /// 根據資料訪問索引 /// </summary> /// <param name="value"></param> /// <returns></returns> public int Locate(T value) { Node<T> temp = _head; if (temp.Data == null) { return -1; } int index = 0; while (true) { if (temp.Data.Equals(value)) { return index; } else { if (temp.Next != null) { temp = temp.Next; } else { break; } } } return -1; } #endregion }View Code