熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

C#與數據結構

2022-06-13   來源: .NET編程 

   ArrayList
    如果要動態地改變數組所占用內存空間的大小則需以數組為基礎進一步抽象以實現這個功能以圖的學生宿捨為例為了使A班的所學生住在連續的宿捨內可以把A班的學生全部搬遷到連續的間空宿捨內其效果如圖所示

    現實中為了讓一個班新加入的個學生能跟原來的學生住在一起而把班級整體搬遷這樣的做法顯示不合適因為搬遷的成本太高但在計算機中內存成片區域間的拷貝成本是非常低的這樣的解決方案是合理可行的

  但是這個解決方案還存在問題如果一個班級頻繁地有新學生加入為了保證學生能住在連續的宿捨內整個班級就不得不頻繁地搬遷可以采用以空間換時間的做法來解決這個問題在學生每次搬遷時都讓班級宿捨的數量是原來的兩倍也就是說如果原來一個班級有間宿捨搬遷後就變為再次搬遷則變為如圖所示A班的宿捨為這三間宿捨做為本班備用宿捨不再允許其他班級的學生搬入

  C#中的ArrayList正是采用上述方法來動態改變數組大小的ArrayList又被稱為動態數組它的存儲空間可以被動態改變同時還擁有添加刪除元素的功能

  下面列出了ArrayList的部分核心代碼

    【ArrayListcs】

  using System;
    namespace LinearList
    {
        public class ArrayList
        {
            // 成員變量
            private const int _defaultCapacity = ; //默認初始容量
            private object[] _items; //用於存放元素的數組
            private int _size; //指示當前元素個數
            //當元素個數為零時的數組狀態
            private static readonly object[] emptyArray = new object[];
            // 方法
            public ArrayList() //默認構造方法
            {   //這樣做可以避免元素個數為零時的訪問出錯
                this_items = emptyArray;
            }
            //指定ArrayList初始容量的構造方法
            public ArrayList(int capacity)
            {
                if (capacity < )
                {   //當容量參數為負數時引發異常
                    throw new ArgumentOutOfRangeException(capacity
                        為ArrayList指定的初始容量不能為負數);
                }
                //按照capacity參數指定的長度的值初始化數組
                this_items = new object[capacity];
            }
            //添加一個方法
            public virtual int Add(object value)
            {   //當空間滿時
                if (this_size == this_itemsLength)
                {   //調整空間
                    thisEnsureCapacity(this_size + );
                }
                this_items[this_size] = value; //添加元素
                return this_size++; //使長度加
            }
            //動態調整數組空間
            private void EnsureCapacity(int min)
            {
                if (this_itemsLength < min)
                {   //空間加倍
                    int num = (this_itemsLength == ) ?
                        _defaultCapacity : (this_itemsLength * );
                    if (num < min)
                    {
                        num = min;
                    }
                    //調用Capacity的set訪問器以按照num的值調整數組空間
                    thisCapacity = num;
                }
            }
            //在指定索引入插入指定元素
            public virtual void Insert(int index object value)
            {
                if ((index < ) || (index > this_size))
                {
                    throw new ArgumentOutOfRangeException(index 索引超出范圍);
                }
                if (this_size == this_itemsLength)
                {   //當空間滿時調整空間
                    thisEnsureCapacity(this_size + );
                }
                if (index < this_size)
                {   //插入點後面的所有元素向後移動一位
                    ArrayCopy(this_items index
                        this_items index + this_size index);
                }
                this_items[index] = value; //插入元素
                this_size++; //使長度加
            }
            //移除指定索引的元素
            public virtual void RemoveAt(int index)
            {
                if ((index < ) || (index >= this_size))
                {
                    throw new ArgumentOutOfRangeException(index 索引超出范圍);
                }
                this_size; //使長度減
                if (index < this_size)
                {   //使被刪除元素後的所有元素向前移動一位
                    ArrayCopy(this_items index +
                        this_items index this_size index);
                }
                this_items[this_size] = null; //最後一位空出的元素置空
            }
            //裁減空間使存儲空間正好適合元素個數
            public virtual void TrimToSize()
            {
                thisCapacity = this_size;
            }

  // 屬性
            public virtual int Capacity //指示ArrayList的存儲空間
            {
                get
                {
                    return this_itemsLength;
                }
                set
                {
                    if (value != this_itemsLength)
                    {
                        if (value < this_size)
                        {
                            throw new ArgumentOutOfRangeException(value 容量太小);
                        }
                        if (value > )
                        {   //開辟一塊新的內存空間存儲元素
                            object[] destinationArray = new object[value];
                            if (this_size > )
                            {   //把元素搬遷到新空間內
                                ArrayCopy(this_items
                                    destinationArray this_size);
                            }
                            this_items = destinationArray;
                        }
                        else //最小空間為_defaultCapacity所指定的數目這裡是
                        {
                            this_items = new object[_defaultCapacity];
                        }
                    }
                }
            }
            public virtual int Count //只讀屬性指示當前元素個數
            {
                get
                {
                    return this_size;
                }
            }
            public virtual object this[int index] //索引器
            {
                get //獲取指定索引的元素值
                {
                    if ((index < ) || (index >= this_size))
                    {
                        throw new ArgumentOutOfRangeException(index 索引超出范圍);
                    }
                    return this_items[index];
                }
                set //設置指定索引的元素值
                {
                    if ((index < ) || (index >= this_size))
                    {
                        throw new ArgumentOutOfRangeException(index 索引超出范圍);
                    }
                    this_items[index] = value;
                }
            }
        }
    }

  


    上述代碼通過在一個數組(第行代碼的成員變量_items)的基礎上做進一步抽象構建了一個可動態改變空間的順序表ArrayList並實現了一些基礎操作下面對之進行一一介紹

      初始化

  這裡實現了種初始方法第一種為行代碼它把順序表空間初始化為一個長度數組這樣做的目的是為了調用方便做為成員變量的object類型數組_items默認會被初始化為null如果不把它初始化為長度數組在使用代碼 ArrayList arr = new ArrayList() 來創建ArrayList後試圖訪問它的Count屬性將會導致錯誤發生

  第二種初始化方法為行代碼它根據capacity參數所指定的值來初始化_items數組的長度如果初始化一個長度為的ArrayList數組可以使用如下代碼

  ArrayList arr = new ArrayList()

  當可以預見ArrayList所操作的大概元素個數時使用這種方法可以在一定程序上避免數組重復創建和數據遷移以提高性能和減少內存垃圾回收的壓力

      動態改變存儲空間操作

  行的EnsureCapacity(int min)方法用於空間不足時使空間加倍從代碼

  int num = (this_itemsLength == ) ? _defaultCapacity : (this_itemsLength * );

  可以得知當元素個數為空間增長為否則將翻倍改變空間大小的代碼是在Capacity屬性中的set訪問器中實現的(代碼行)代碼

  object[] destinationArray = new object[value];

  創建了一個新的object數組它在內存中開辟了一個新的空間用於存放元素代碼

  ArrayCopy(this_items destinationArray this_size);

  把_items數組中的元素全部拷貝到新數組destinationArray中可以把它理解為數據搬新家最後通過

  this_items = destinationArray;

  使用於存放數據的成員變量_items指向新的數組對象destinationArray

  行的TrimToSize()方法用於裁減多余空間實際的裁減操作也是在Capacity屬性中的set訪問器中實現這個操作也會導致數組的重新創建和數據遷移建議一般情況下不使用此操作除非集合中的剩余空間很多

      元素的讀寫操作

  行代碼實現了一個索引器這樣就可以使用中括號加索引號來讀取和給元素賦值使ArrayList的使用看上去和數組很相似

      元素的添加和插入操作

  行的Add(object value)方法實現了添加元素的功能元素添加在集合的末尾成員變量_size用於指示當前元素個數它總是指向集合中的最後一個元素

  行的Insert(int index object value)方法用於在指定索引處插入一個元素為了保證順序表中的每個元素物理上相鄰插入點後面的所有元素都將後移一位其效果如圖(a)所示

        元素的刪除操作

  行的RemoveAt(int index)方法用於刪除指定索引的元素刪除指定元素後刪除點後的所有元素將向前移動一位其效果如圖(b)所示

  下面對ArrayList類進行測試

  【例】ArrayList的使用

  新建一個控制台應用程序並在項目中把上面的ArrayListcs文件做為一個【現有項】添加進去在代碼窗體前面使用如下語句加入LinearList命名空間



 using LinearList;

  並在Main方法中輸入如下代碼

  using System;
    using LinearList;

  namespace Demo_
    {
        class Program
        {
            static void Main(string[] args)
            {
                ArrayList arr = new ArrayList();
                ConsoleWriteLine(arr現在的容量為 + arrCapacity +   長度為: + arrCount);
                arrAdd(); //添加一個元素
                ConsoleWriteLine(arr現在的容量為 + arrCapacity +   長度為: + arrCount);
                for (int i = ; i <= ; i++)
                {   //添加個元素完成後元素總數達到
                    arrAdd(i);
                }
                ConsoleWriteLine(arr現在的容量為 + arrCapacity +   長度為: + arrCount);
                for (int i = ; i <= ; i++)
                {   //添加個元素完成後元素總數達到
                    arrAdd(i);
                }
                ConsoleWriteLine(arr現在的容量為 + arrCapacity +   長度為: + arrCount);
                for (int i = ; i < arrCount; i++) //打印所有元素
                {
                    ConsoleWrite(i +   );
                }
                //刪除兩個元素
                arrRemoveAt(arrCount );
                arrRemoveAt(arrCount );
                ConsoleWriteLine(); //換行
                for (int i = ; i < arrCount; i++) //打印所有元素
                {
                    ConsoleWrite(i +   );
                }
                ConsoleWriteLine(); //換行
                ConsoleWriteLine(arr現在的容量為 + arrCapacity +   長度為: + arrCount);
                arrTrimToSize(); //載減多余空間
                ConsoleWriteLine(arr現在的容量為 + arrCapacity +   長度為: + arrCount);
                ConsoleReadLine();
            }
        }
    }


    運行結果如圖所示



    由運行結果可以得知數組對象arr的容量隨著元素的不斷增加不斷改變在刪除兩個元素之後容量還保持在不變在通過調用TrimToSize()裁減空間後容量最終變為

   類型安全
    數組和ArrayList的本質區別在於前者是類型安全的而後者不是類型安全的ArrayList為了兼容所有類型的對象使用了object數組這給使用帶來了一些的麻煩如下例所示

  【例】數組和ArrayList的對比

  本例使用了C#類庫中的ArrayList而不是前面自定義的ArrayList它存在於SystemCollections命名空間中新建一個控制台應用程序引入SystemCollections命名空間並在Main()方法中輸入如下代碼

 using System;
    using SystemCollections;
    namespace Demo_
    {
        class Program
        {
            static void Main(string[] args)
            {
                int[] arr = new int[];
                arr[] = ;
                arr[] = ;
                int result = arr[] * arr[];
                ConsoleWriteLine(result);
                ArrayList arrL = new ArrayList();
                arrLAdd();
                arrLAdd();
                result = (int)arrL[] * (int)arrL[];
                ConsoleWriteLine(result);
                ConsoleReadLine();
            }
        }
    }

  運行結果

  

  


    本例使用數組和ArrayList分別做了相同的事情但使用方法卻大相徑庭首先數組在創建時就已經確定只接收int類型數據並且它的長度是固定的而ArrayList則可以接收任意object類型而事實上C#中的所有類均是object類型的子類

  其次數組沒有添加元素的功能因為在數組創建時各個元素就已經存在只是被初始化為而已只能通過下標改變各個元素的值而ArrayList只有把元素添加進去後才可以通過下標訪問相應的元素

  最後在使用集合中的元素時數組不需要進行強制類型轉換而ArrayList必須要經過強制類型轉換才能使用這是因為ArrayList實際存放的是object對象要按照這些對象原本的類型來使用就必須要使用強制類型轉換

  ArrayList的這個特點帶來了類型安全問題

  ArrayList arrL = new ArrayList();
    arrLAdd();
    arrLAdd(Hello World);
    arrLAdd(new Button());

  以上代碼在集合中存放了各種各樣的數據類型但這樣做是被允許的這種類型的不安全一方面給程序帶來了隱患另一方面如果集合中存放的是值類型還會產生裝箱和拆箱操作降低了程序的性能

  NET 版本的泛型的出現完美地解決了上述問題新版本使用SystemCollectionsGeneric命名空間下的List<T>類取代了原來的ArrayList類下面演示了泛型List<T>類的使用

  List<int> arrL=new List<int>();
    arrLAdd();
    arrLAdd();

  可以看到第一行代碼在集合創建時就已經把元素類型限定為int它是類型安全的同時避免了裝箱和拆箱操作強烈建議在實際編程中使用List<T>代替ArrayList


From:http://tw.wingwit.com/Article/program/net/201311/12729.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.