Bitmap算法

  在全部具備性能優化的數據結構中,我想你們使用最多的就是hash表,是的,在具備定位查找上具備O(1)的常量時間,多麼的簡潔優美,web

可是在特定的場合下:算法

①:對10億個不重複的整數進行排序。數組

②:找出10億個數字中重複的數字。性能優化

固然我只有普通的服務器,就算2G的內存吧,在這種場景下,咱們該如何更好的挑選數據結構和算法呢?服務器

 

一:問題分析數據結構

     這年頭,大牛們寫的排序算法也就那麼幾個,首先咱們算下放在內存中要多少G: (10億 * 32)/(1024*1024*1024*8)=3.6G,可憐數據結構和算法

的2G內存直接爆掉,因此各類神馬的數據結構都玩不起來了,固然使用外排序仍是能夠解決問題的,因爲要走IO因此暫時剔除,由於咱們ide

要玩高性能,無望後咱們想一想可不能夠在二進制位上作些手腳?  性能

好比我要對{1,5,7,2}這四個byte類型的數字作排序,該怎麼作呢?咱們知道byte是佔8個bit位,其實咱們能夠將數組中的值做爲bit位的優化

key,value用」0,1「來標識該key是否出現過?下面看圖:

從圖中咱們精彩的看到,咱們的數組值都已經做爲byte中的key了,最後我只要遍歷對應的bit位是否爲1就能夠了,那麼天然就成有序數組了。

可能有人說,我增長一個13怎麼辦?很簡單,一個字節能夠存放8個數,那我只要兩個byte就能夠解決問題了。

能夠看出我將一個線性的數組變成了一個bit位的二維矩陣,最終咱們須要的空間僅僅是:3.6G/32=0.1G便可,要注意的是bitmap排序不

是N的,而是取決於待排序數組中的最大值,在實際應用上關係也不大,好比我開10個線程去讀byte數組,那麼複雜度爲:O(Max/10)。

 

二:代碼

  我想bitmap的思想你們都清楚了,這一次又讓咱們見證了二進制的魅力,固然這些移位都是位運算的工做了,熟悉了你就玩轉了。

1:Clear方法(將數組的全部bit位置0)

   好比要將當前4對應的bit位置0的話,只須要1左移4位取反與B[0] & 便可。

複製代碼
 1         #region 初始化所用的bit位爲0
 2         /// <summary>
 3         /// 初始化所用的bit位爲0
 4         /// </summary>
 5         /// <param name="i"></param>
 6         static void Clear(byte i)
 7         {
 8             //至關於 i%8 的功能
 9             var shift = i & 0x07;
10 
11             //計算應該放數組的下標
12             var arrindex = i >> 3;
13 
14             //則將當前byte中的指定bit位取0,&後其餘對方數組bit位必然不變,這就是 1 的妙用
15             var bitPos = ~(1 << shift);
16 
17             //將數組中的指定bit位置一  「& 操做」
18             a[arrindex] &= (byte)(bitPos);
19         }
20         #endregion
複製代碼

 

2:Add方法(將bit置1操做)

  一樣也很簡單,要將當前4對應的bit位置1的話,只須要1左移4位與B[0] | 便可。

複製代碼
 1 #region 設置相應bit位上爲1
 2         /// <summary>
 3         /// 設置相應bit位上爲1
 4         /// </summary>
 5         /// <param name="i"></param>
 6         static void Add(byte i)
 7         {
 8             //至關於 i%8 的功能
 9             var shift = i & 0x07;
10 
11             //計算應該放數組的下標
12             var arrindex = i >> 3;
13 
14             //將byte中的 1 移動到i位
15             var bitPos = 1 << shift;
16 
17             //將數組中的指定bit位置一  「| 操做」
18             a[arrindex] |= (byte)bitPos;
19         }
20         #endregion
複製代碼

 

2:Contain方法(判斷當前bit位是不是1)

    若是看懂了Clear和Add,我相信最後一個方法已經不成問題了。

複製代碼
 1         #region 判斷當前的x在數組的位中是否存在
 2         /// <summary>
 3         ///判斷當前的x在數組的位中是否存在
 4         /// </summary>
 5         /// <param name="i"></param>
 6         /// <returns></returns>
 7         static bool Contain(byte i)
 8         {
 9             var j = a[i >> 3] & (1 << (i & 0x07));
10 
11             if (j == 0)
12                 return false;
13             return true;
14         }
15         #endregion
複製代碼

最後上總的代碼:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading;
using System.IO;

namespace ConsoleApplication2
{
    public class Program
    {
        static byte n = 7;

        static byte[] a;

        public static void Main()
        {
            //節省空間的作法
            a = new byte[(n >> 3) + 1];

            for (byte i = 0; i < n; i++)
                Clear(i);

            Add(4);
            Console.WriteLine("插入4成功!");

            var s = Contain(4);

            Console.WriteLine("當前是否包含4:{0}", s);

            s = Contain(5);

            Console.WriteLine("當前是否包含5:{0}", s);

            Console.Read();
        }

        #region 初始化所用的bit位爲0
        /// <summary>
        /// 初始化所用的bit位爲0
        /// </summary>
        /// <param name="i"></param>
        static void Clear(byte i)
        {
            //至關於 i%8 的功能
            var shift = i & 0x07;

            //計算應該放數組的下標
            var arrindex = i >> 3;

            //則將當前byte中的指定bit位取0,&後其餘對方數組bit位必然不變,這就是 1 的妙用
            var bitPos = ~(1 << shift);

            //將數組中的指定bit位置一  「& 操做」
            a[arrindex] &= (byte)(bitPos);
        }
        #endregion

        #region 設置相應bit位上爲1
        /// <summary>
        /// 設置相應bit位上爲1
        /// </summary>
        /// <param name="i"></param>
        static void Add(byte i)
        {
            //至關於 i%8 的功能
            var shift = i & 0x07;

            //計算應該放數組的下標
            var arrindex = i >> 3;

            //將byte中的 1 移動到i位
            var bitPos = 1 << shift;

            //將數組中的指定bit位置一  「| 操做」
            a[arrindex] |= (byte)bitPos;
        }
        #endregion

        #region 判斷當前的x在數組的位中是否存在
        /// <summary>
        ///判斷當前的x在數組的位中是否存在
        /// </summary>
        /// <param name="i"></param>
        /// <returns></returns>
        static bool Contain(byte i)
        {
            var j = a[i >> 3] & (1 << (i & 0x07));

            if (j == 0)
                return false;
            return true;
        }
        #endregion
    }
}
View Code

相關文章
相關標籤/搜索