1. 程式人生 > >資料結構複習---順序表和單鏈表

資料結構複習---順序表和單鏈表

1.前言:

最近比較浮躁,想學習一門新的技術卻總是淺嘗輒止,遇到不懂的地方就想跳過去,時間長了,心態就有點崩了。靜下心來,去喝了幾碗心靈雞湯。雞湯博主感動到了我:"無專注,無風景。不要太貪心,一次只做一件事,而且只做最重要的事。".於是乎,我把家裡翻了個底朝天,找到了我墊在床底下的《資料結構》這本書,覺得自己是時候靜下心來好好複習一下基礎了。今天剛看到順序表和連結串列,把我的學習心得記錄在這裡。也希望自己能堅持,老老實實的把這本書複習完。

2.資料結構的重要性:

講一門知識之前,通常流程都是要是先吹一波這個東西的重要性,資料結構和演算法雖然已經被吹上天了,我還是覺得有必要:眾所周知,資料結構是計算機專業中最重要的課程之一,可是為什麼呢?用處太多難以列舉,總結成一句話就是:可以讓你的程式跑更快

。今天主要一下順序表和單鏈表的原理和實現

3.順序表:

順序表是最簡單,最常用,最基本的資料結構

特點:1.結構中的元素存在1對1的線性關係,這種1對1的關係指的是資料元素之間的關係

    2.位置有先後關係,除第一個位置的元素外,其他位置的元素前面都只有一個數據元素,相反除最後一個位置的資料元素外,其他位置的資料元素後面都只有一個元素。

CLR中的實現:List<T>

 順序表儲存結構:

 

c#實現順序表(程式碼中只實現了順序表的基本功能,沒有去做健壯性處理):

  /// <summary>
    ///
順序表 /// </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 }
View Code

 

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