C#中如何優化列表遍歷速度


一個數據庫表(id,name,…)中有10萬條記錄,查找name=’guoguo‘可能需要很長時間,但是如果對name建立了索引,那么再用name=’guoguo‘來查詢將變得非常快(有多快?自己可以去試試)。

相應的,有時候我們的代碼里面會用到List<T>,Array來存儲一組數據。我們以一個例子來說明一下。

定義數據類型: 

    public class UserInfo
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
    }

示例代碼有個前提:name不會重復。從List中按照name找到對應的UserInfo可以用以下代碼:

        List<UserInfo> _userinfos;

        public UserInfo GetUserInfoByName(string name)

        {

            for (int i = 0; i < _userinfos.Count; i++)

            {

                UserInfo ui = _userinfos[i];

                if (ui.Name == name)

                {

                    return ui;

                }

            }

            return null;

        }

 

        public UserInfo GetUserInfoByName_Find(string name)

        {

            return _userinfos.Find((temp) =>

            {

                return temp.Name == name;

            });

        }

兩個方法其實都是使用遍歷列表的方式去比較、查找;我做了實驗,如果列表中有10萬條記錄,分別執行“查找第5萬個元素”1000遍的耗時為:

GetUserInfoByName

1877毫秒

GetUserInfoByName_Find

2290毫秒

也就是說平均一次要2毫秒左右(Find效率還更低);

OK,接下來我們要試着借鑒數據庫的方式給List建立索引。 

        public List<UserInfo> Userinfos

        {

            get { return _userinfos; }

            set

            {

                _userinfos = value;

                MakeIndex();

            }

        }

 

        Dictionary<string, UserInfo> _userIndex;

 

        /// <summary>

        /// 建立索引

        /// </summary>

        private void MakeIndex()

        {

            Dictionary<string, UserInfo> userIndex = new Dictionary<string, UserInfo>();

            foreach (var item in _userinfos)

            {

                userIndex.Add(item.Name, item);

            }

            _userIndex = userIndex;

        }

MakeIndex方法在Userinfos的set屬性器里面調用;那么查詢的方法就應該這么寫: 

        public UserInfo GetUserInfoByNameEx(string name)

        {

            return _userIndex[name];

        }

這么簡單?對,就是這么簡單,而且,效率特別高。與上面的兩個方法一起進行比較:

建立索引+查找10萬次=36毫秒!

原因就是Dictionary[Key]方法的時間復雜度為O(1),幾乎不耗時。

注意:本示例為了代碼簡潔,對於key重復,null引用等等都沒有判斷,實際編碼過程中請注意考慮這些情況。

以下是示例的所有代碼:

using System;

using System.Collections.Generic;

using System.Diagnostics;

 

namespace ConsoleApplication1

{

    class Program

    {

 

        static void Main(string[] args)

        {

            List<UserInfo> userinfos = new List<UserInfo>();

            //創建10萬個數據

            for (int i = 0; i < 10 * 10000; i++)

            {

                UserInfo ui = new UserInfo();

                ui.ID = i;

                ui.Name = Guid.NewGuid().ToString();

                userinfos.Add(ui);

            }

            UserUtil util = new UserUtil();

            //用於計時

            Stopwatch sw = new Stopwatch();

            sw.Start();

            util.Userinfos = userinfos;

            sw.Stop();

            Console.WriteLine(string.Format("建立索引MakeIndex耗時:{0}毫秒", sw.ElapsedMilliseconds));

 

            //以第5萬個名字作為要查找的名字

            string nameToFind = userinfos[5 * 10000].Name;

            sw.Reset();

            sw.Start();

            for (int i = 0; i < 1000; i++)

            {

                util.GetUserInfoByName(nameToFind);

            }

            sw.Stop();

            Console.WriteLine(string.Format("執行1000次GetUserInfoByName耗時:{0}毫秒", sw.ElapsedMilliseconds));

 

            sw.Reset();

            sw.Start();

            for (int i = 0; i < 1000; i++)

            {

                util.GetUserInfoByName_Find(nameToFind);

            }

            sw.Stop();

            Console.WriteLine(string.Format("執行1000次GetUserInfoByName_Find耗時:{0}毫秒", sw.ElapsedMilliseconds));

 

            sw.Reset();

            sw.Start();

            for (int i = 0; i < 10 * 10000; i++)

            {

                util.GetUserInfoByNameEx(nameToFind);

            }

            sw.Stop();

            Console.WriteLine(string.Format("執行10萬次GetUserInfoByNameEx耗時:{0}毫秒", sw.ElapsedMilliseconds));

 

            Console.ReadKey();

        }

    }

 

    public class UserUtil

    {

        List<UserInfo> _userinfos;

 

        public List<UserInfo> Userinfos

        {

            get { return _userinfos; }

            set

            {

                _userinfos = value;

                MakeIndex();

            }

        }

 

        Dictionary<string, UserInfo> _userIndex;

 

        public UserInfo GetUserInfoByName(string name)

        {

            for (int i = 0; i < _userinfos.Count; i++)

            {

                UserInfo ui = _userinfos[i];

                if (ui.Name == name)

                {

                    return ui;

                }

            }

            return null;

        }

 

        public UserInfo GetUserInfoByName_Find(string name)

        {

            return _userinfos.Find((temp) =>

            {

                return temp.Name == name;

            });

        }

       

        /// <summary>

        /// 建立索引

        /// </summary>

        private void MakeIndex()

        {

            Dictionary<string, UserInfo> userIndex = new Dictionary<string, UserInfo>();

            foreach (var item in _userinfos)

            {

                userIndex.Add(item.Name, item);

            }

            _userIndex = userIndex;

        }

 

        public UserInfo GetUserInfoByNameEx(string name)

        {

            return _userIndex[name];

        }

 

    }

 

    public class UserInfo

    {

        public int ID { get; set; }

        public string Name { get; set; }

        public int Age { get; set; }

    }

}
示例代碼

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM