浪客劍心:位圖法Bitmap算法分析


看了博客園里一篇文章《一道騰訊前端試題,誰來試試身手》,正好以前了解過位圖法,確實不錯。位圖法適用於大規模數據,但數據狀態又不是很多的情況。通常是用來判斷某個數據存不存在,如可標記1為存在,0為不存在。

  位圖法網上資料比較少,我在百度百科找到了對它的描述


位圖法比較適合於如下這種情況,它的做法是按照集合中最大元素max創建一個長度為max+1的新數組,然后再次掃描原數,遇到幾就給新數組的第幾位置上1,如遇到 5就給新數組的第六個元素置1,這樣下次再遇到5想置位時發現新數組的第六個元素已經是1了,這說明這次的數據肯定和以前的數據存在着重復。這種給新數組初始化時置零其后置一的做法類似於位圖的處理方法故稱位圖法。它的運算次數最壞的情況為2N。如果已知數組的最大值即能事先給新數組定長的話效率還能提高一倍。

 

  效率測試(參考一道騰訊前端試題,誰來試試身手):

  傳統的雙重循環查找也是可取的,但效率實在不敢恭維,特別是處理大量數據時候

  

 class Program
    {
        static void Main(string[] args)
        {

            //產生隨機數
            int[] array = Enumerable.Range(1, 100000).OrderBy
(n => Guid.NewGuid()).Take(80000).ToArray();
      
            DateTime dt1 = DateTime.Now;

            int max = array[0];
            int flag;
            //數組無序排列,查找最大值
            for (int i = 1; i < array.Length; i++)
            {
                if (array[i] > max)
                {
                    max = array[i];
                }
            }
            for (int i = 1; i <= max; i++)
            {
                flag = 1;
                for (int j = 0; j < array.Length; j++)
                {
                    //相等標記Flag=0,意味着不是缺少的數字
                    if (i.Equals(array[j]))
                    {
                        flag = 0;
                        break;
                    }

                }
                if (flag == 1)
                {
                    Console.Write("{0},", i);
                }

            }
            DateTime dt2 = DateTime.Now;
            TimeSpan ts = dt2 - dt1;
            Console.WriteLine("\r\n" + "共耗時間{0}ms", ts.TotalMilliseconds);//52730.5525
            Console.ReadKey();
        }
    }

測試結果:數據量小時,還OK,數據量大的情況下,顯示很卡很緩慢,最壞的時間復雜度:T(n)=O(n*n)

以上測試,總時間約為:51291.2996MS

位圖法測試

  class Program
    {
        static void Main(string[] args)
        {


            //隨即產生80000個不重復數
            int[] array = Enumerable.Range(1, 100000).OrderBy
(n => Guid.NewGuid()).Take(80000).ToArray();
          
            //int[] array={1,2,3,5,7,9,10,12,45,62,55,78,98,52,12,4,200,60,63,65,66,67,68,69,70,74,79,80,82,89,90,91,92,93,94,98,100,101};
            DateTime dt1=DateTime.Now;
            
            //找出最大值
            int max=array[0];
            for (int i = 1; i < array.Length; i++)
            {
                if (array[i]>max)
                {
                    max = array[i];
                }
            }
            //新數組的長度為舊數組最大數字+1
            int[] lose=new int[max+1];
            foreach (int item in array)
            {
                //若Item為2,則Lose[2]=1...所以新數組的長度為舊數組最大數字+1
                lose[item] = 1;
            }
            //那么為0的就是缺少值
            for (int i = 1; i < lose.Length; i++)//100
            {
                if (lose[i].Equals(0))
                {
                    Console.Write("{0},",i);
                }
            }
            DateTime dt2=DateTime.Now;
            Console.WriteLine("\r\n"+(dt2-dt1).TotalMilliseconds);//6004.3379Ms
            Console.ReadKey();

        }
    }

位圖法在確定最大數值后的時間復雜度還是挺樂觀的,最壞情況:T(n)=O(2n)

屏幕飛快的刷新着,測試時間約是:6295.3601MS

總結

判斷集合中是否存在重復元素或者查找缺失元素是常見編程任務之一,當集合中數據量比較大時我們通常希望少進行幾次掃描,這時雙重循環法就不可,位圖法Bitmap可以考慮。


免責聲明!

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



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