• 打造比Dictionary还要快2倍以上的字查找类


    针对一个长度为n的数组。

    [1,2,3,4,5,6,7,8,9]

    最快的通用查找类是Dictionary其采用hashcode算法,复杂度为O(1).

    而上大学时,最快的查找法为二分查找法,复杂度为O(log(n)).

    因此我们得出结论,Dictionary的查找速度应该是最快的。

    但是Dictionary里在查找之前必须执行GetHashCode()计算出hashCode.

    因此查找效率就是计算hashCode的效率。

    如果某种查找算法比计算hashCode的时间要短,也就能超越Dictionary的查找效率。

    因此,我开始想办法打造这个查找函数。

    //继承原生的查找类

    public class FastDictionary<TValue>:Dictionary<string,TValue>{}

    //自定义的查找类

    public class FastSearch<TValue>{

    }

    首先两个字符串的对比一般情况下是

    public bool compare(string strA,string strB)

    {

      for(int i=0;i<strA.Length;i++)

      {

        if(strA[i]!=strB[i])

        {

          return false;

        }

      }

      return true;

    }

    以上的情况是对两个字符串中的每一个字符做对比,如果所有的字符都相同,则代表两个字符串相同。

    很好理解。但其实还有更快的算法。

    在C#中所有的字符串为utf-16格式,即两个字节代表一个字符。而一个long类型是8个字节。也就是说,一个long类型可以存储4个字符。

    那么以上的对比函数可以这样写:

    public bool Compare(string strA,string strB)
    {
      int length=0;
      int longLength=(length+3)>>2;
      int remain=0;
      fixed(char* ptA=&strA) fixed(char* ptB=&strB)
      {
        for(int i=0;i<longLength;i++)
        {
          if(i==longLength-1)
          {
            remain=length&3;
            if(remain==0)
            {
              if(*(long*)(ptA+i*4)==*(long*)(ptB+i*4))
              {
                return false;
              }
            }
            else if(remain==1)
            {
              if(*(short*)(ptA+i*4)==*(short*)(ptB+i*4))
              {
                return false;
              }
            }
            else if(remain==2)
            {
              if(*(int*)(ptA+i*4)==*(int*)(ptB+i*4))
              {
                return false;
              }
            }
            else if(remain==3)
            {
              if(*(long*)(ptA+i*4-1)==*(long*)(ptB+i*4-1))
              {
                return false;
              }
            }
          }
          if(*(long*)(ptA+i*4)==*(long*)(ptB+i*4))
          {
            return false;
          }
        }
        return true;
      }
    }

    当字符串中的字符为五个时。前四个字符串转为long类型。第五个字符串转为short类型,然后再转存为long类型

    ['a','b','c','d','e']

    当字符串中的字符为六个时,前四个字符串转为long类型。第五,六个字符串转为int类型,然后再转存为long类型

    ['a','b','c','d','e','f']

    当字符串中的字符为七个时,前四个字符串转为long类型。第四,五,六,七个字符转为long类型

    ['a','b','c','d','e','f','g']

    当字符串中的字符为八个时,前四个字符串转为long类型。后四个字符转为long类型

    ['a','b','c','d','e','f','g','h']

    也就是说,所有的字符串都能转为long数组。

    long[] strLong=getLongArray("sdfasdfsfd");

    然后再对long数组对行对比,那么效率也快多了。

    再进一步,在Compare函数中,需要不断的判断length的长度,以及判断是否是最后一个字符。

    其实在已经确定了字符串长度的时候,这些判断代码是不需要的。

    因此,可以利用Emit生成对比函数缓存代理,然后再执行,这样的字符串对比效率应该是最快的。

    当然最好是在64位操作系统下,这样处理long类型效率比32位系统快。

    下面是生成字符串对比的函数的代理函数

            public unsafe delegate bool CompareDelegate(char* keyChar, char* CompareKeyChar,int length);
            public static CompareDelegate GetCompareDelegate(int length)
            {
                TypeBuilder typeBuilder = UnSafeHelper.GetDynamicType();
                MethodBuilder dynamicMethod= typeBuilder.DefineMethod("Compare", MethodAttributes.Public 
                    | MethodAttributes.Static | MethodAttributes.HideBySig, CallingConventions.Standard, 
                    typeof(bool),new Type[]{ typeof(char*),typeof(char*),typeof(int) });
                ILGenerator methodIL= dynamicMethod.GetILGenerator();
    
                #region
                var fourCount = methodIL.DeclareLocal(typeof(int));
                //var position = methodIL.DeclareLocal(typeof(int));
                var remain = methodIL.DeclareLocal(typeof(int));
                
                int position = 0;
                var fourEnd = methodIL.DefineLabel();
                var methodEnd = methodIL.DefineLabel();
                while (position < (length & ~3))
                {
                   
                    methodIL.Emit(OpCodes.Ldarg_0);
                    methodIL.Emit(OpCodes.Ldc_I4, position*2);
                    methodIL.Emit(OpCodes.Add);
                    methodIL.Emit(OpCodes.Ldind_I8);
    
                    methodIL.Emit(OpCodes.Ldarg_1);
                    methodIL.Emit(OpCodes.Ldc_I4, position * 2);
                    methodIL.Emit(OpCodes.Add);
                    methodIL.Emit(OpCodes.Ldind_I8);
    
                    methodIL.Emit(OpCodes.Beq_S, fourEnd);
                    methodIL.Emit(OpCodes.Ldc_I4_0);//false
                    methodIL.Emit(OpCodes.Ret);
                    position += 4;
                }
                methodIL.MarkLabel(fourEnd);
                switch (length & 3)
                {
                    case 1: {
                            methodIL.Emit(OpCodes.Ldarg_0);
                            methodIL.Emit(OpCodes.Ldc_I4, position*2);
                            methodIL.Emit(OpCodes.Add);
                            methodIL.Emit(OpCodes.Ldind_I2);
    
                            methodIL.Emit(OpCodes.Ldarg_1);
                            methodIL.Emit(OpCodes.Ldc_I4, position*2);
                            methodIL.Emit(OpCodes.Add);
                            methodIL.Emit(OpCodes.Ldind_I2);
    
                            methodIL.Emit(OpCodes.Beq_S, methodEnd);
                            methodIL.Emit(OpCodes.Ldc_I4_0);
                            methodIL.Emit(OpCodes.Ret);
                        } break;
                    case 2: {
                            methodIL.Emit(OpCodes.Ldarg_0);
                            methodIL.Emit(OpCodes.Ldc_I4, position * 2);
                            methodIL.Emit(OpCodes.Add);
                            methodIL.Emit(OpCodes.Ldind_I4);
    
                            methodIL.Emit(OpCodes.Ldarg_1);
                            methodIL.Emit(OpCodes.Ldc_I4, position * 2);
                            methodIL.Emit(OpCodes.Add);
                            methodIL.Emit(OpCodes.Ldind_I4);
    
                            methodIL.Emit(OpCodes.Beq_S, methodEnd);
                            methodIL.Emit(OpCodes.Ldc_I4_0);
                            methodIL.Emit(OpCodes.Ret);
                        } break;
                    case 3: {
                            position--;
                            methodIL.Emit(OpCodes.Ldarg_0);
                            methodIL.Emit(OpCodes.Ldc_I4, position * 2);
                            methodIL.Emit(OpCodes.Add);
                            methodIL.Emit(OpCodes.Ldind_I8);
    
                            methodIL.Emit(OpCodes.Ldarg_1);
                            methodIL.Emit(OpCodes.Ldc_I4, position * 2);
                            methodIL.Emit(OpCodes.Add);
                            methodIL.Emit(OpCodes.Ldind_I8);
    
                            methodIL.Emit(OpCodes.Beq_S, methodEnd);
                            methodIL.Emit(OpCodes.Ldc_I4_0);
                            methodIL.Emit(OpCodes.Ret);
                        } break;
                }
                #endregion
                methodIL.MarkLabel(methodEnd);
                methodIL.Emit(OpCodes.Ldc_I4_1);
                methodIL.Emit(OpCodes.Ret);
                Type t= typeBuilder.CreateType();
                MethodInfo method= t.GetMethod("Compare");
                
                Delegate delete = Delegate.CreateDelegate(typeof(CompareDelegate), method);
                return (CompareDelegate)delete;
            }        

    那么基于对以上函数的认识,有两个是需要明确的。

    1.利用Emit可以省略掉一部分判断代码。

    2.利用long类型可以一次判断4个字符,加快字符串的对比速度。

    那么字符串的查找问题就能转换为long类型的查找问题。这时候很容易就能想到二分查找。

    假如有以下字符串。

    string[] keys={“aa”,"bb","ccc","dddd"};

    从中查出"bb"字符串所在的索引。

    先根据字符串中的字符转为byte整型

    ['a','a']=>[97,97,0,0]

    ['b','b']=>[98,98,0,0]

    ['c','c','c']=>[99,99,99,0]

    ['d','d','d','d']=>[100,100,100,100]

    那么整体的二维数组为:

    [097,097,000,000]

    [098,098,000,000]

    [099,099,099,000]

    [100,100,100,100]

    是不是很像高数中的矩阵?

    那么这个二维数组共四行四列。

    在第一列中有97,98,99,100四个值。

    这四个值先进行排序。然后再选出中间值。利用二分法。进行代码生成。

    即:if(str[0]<99){}else{}

    或:if(str[0]>98{}else{}.

    这样的话,就可以把以上四组分为两组。

    即组A:

    [097,097,000,000]

    [098,098,000,000]

    与组B:

    [099,099,099,000]

    [100,100,100,100]

    在组A中。再利用二分法。

    if(str[0]<98){

      return 0;//数组下标

    }else{

      return 1;

    }

    在组B中。利用二分法.

    if(str[0]<100){

      return 2;

    }else{

      return 3;

    }

    这种近似的二分查找法,应该是查找速度非常快的。下面整理一下思路。

    1.首先把数组转换为整数数组。

    2.对二维数组中的第一列进行排序,找出中间值。

    3.如果第一列中没有找到中间值,就查找第二列。直到找到最优的中间值为止。

    4.根据最优中间值生成if...else...代码。并把二维数据分为二组。

    5.再根据以上思路继续分组,直到不能分为止。

    6.返回所在字符串的数组索引。

    但是以上思路存在一个问题。如果字符串的长度不固定。其中长度较短的字符串需要用0补位。

    也就是说在取值的时候需要判断字符串的长度。

    也就是说,整体思路,应该是这样。

    首先,把一组字符串中相同长度的字符串进行分组。

    然后再利用以上的方法生成近似的二分查找函数。

    那么相同长度的字符串分组需要一个函数进行查找。

    分组数据为:

        public class GroupData<TValue>
        {
            //字符串长度
            public int length;
            //优化的二分查找函数,长度固定
            public FindDelegate findDelegate;
            //优化过的字符串比较函数
            public CompareDelegate compareDelegate;
            public List<KV<TValue>> list;
        }

    其中List<KV<TValue>> list是存储字符串的列表。KV是一个存储key以及value的泛型体。key为string类型:

        public struct KV<TValue>
        {
            public KV(string key, TValue value,int index)
            {
                this.key = key;
                this.length = key.Length;
                this.value = value;
                this.index = index;
            }
            public string key;
            public int length;
            public int index;
            public TValue value;
        }

    整体的搜索类如下:

        public unsafe delegate int FindDelegate(char* keyChar);
        public unsafe delegate bool CompareDelegate(char* keyChar, char* CompareKeyChar,int length);
        public delegate int FindGroupIndexDelegate(int length);
        
        public class FastSearch<TValue> where TValue : class
        {
            GroupData<TValue>[] groupArray;
            public FindGroupIndexDelegate findGroupIndexDelegate;
            public unsafe FastSearch(Dictionary<string, TValue> originalDictionary)
            {
                GroupData<TValue> groupData;
                int index = 0;
                SortedList<int, GroupData<TValue>> groupList = new SortedList<int, GroupData<TValue>>();
                foreach (var kv in originalDictionary)
                {
                    if (groupList.TryGetValue(kv.Key.Length, out groupData))
                    {
                        index = groupList.Count;
                        groupData.list.Add(new KV<TValue>(kv.Key, kv.Value, index));
                    }
                    else
                    {
                        groupData = new GroupData<TValue>();
                        //快速比较函数,应用long指针,一次比较4个字符
                        groupData.compareDelegate = CompareDelegateHelper.GetCompareDelegate(kv.Key.Length);
                        groupData.length = kv.Key.Length;
                        groupData.list = new List<KV<TValue>>();
                        groupData.list.Add(new KV<TValue>(kv.Key, kv.Value, index));
                        groupList.Add(kv.Key.Length, groupData);
                    }
                }
                groupArray = groupList.Values.ToArray();
                groupList.Clear();
                //二分查长相同长度的字符串组下标
                findGroupIndexDelegate = FindGroupIndexDelegateHelper.GetFindGroupIndexDelegate(groupArray);
                for (int i = 0; i < groupArray.Length; i++)
                {
                    //生成在长度相同的字符串中快速查找的函数
                    groupArray[i].findDelegate = FastFindSameLengthStringHelper.GetFastFindSameLengthStringDelegate(groupArray[i].list, groupArray[i].length);
                }
                //originalDictionary.Clear();
            }
            public unsafe bool TryGetValue(string key, int length,out TValue value)
            {
                GroupData<TValue> group = groupArray[findGroupIndexDelegate(length)];
                int index;
                fixed (char* keyChar = key)
                {
                    index = group.findDelegate(keyChar);
                    value = group.list[index].value;
                    string comparekey = group.list[index].key;
                    fixed (char* complareKeyChar = comparekey)
                    {
                        return group.compareDelegate(keyChar, complareKeyChar, length);
                    }
                }
            }
        }

    最前面三个是代理

        public unsafe delegate int FindDelegate(char* keyChar);
        public unsafe delegate bool CompareDelegate(char* keyChar, char* CompareKeyChar,int length);
        public delegate int FindGroupIndexDelegate(int length);

    FindDelegate是查找函数。参数为字符串指针。返回为相同长度字符串列表中的字符串下标。

    CompareDelegate是字符串比较函数。参数为两字符串指针,以及两字符串长度。

    FindGroupIndexDelegate是查找分组的代理函数。

    以上三个代理会在FastSearch初始化的时候初始化。而在查找的时候直接调用。

    其中CompareDelegate的Emit代码前面已经给出。

    FindDelegate的Emit代码为:

        public class FindGroupIndexDelegateHelper
        {
            public static FindGroupIndexDelegate GetFindGroupIndexDelegate<TValue>(GroupData<TValue>[] groupDataArray)
            {
                TypeBuilder typeBuilder = UnSafeHelper.GetDynamicType();
                MethodBuilder dynamicMethod = typeBuilder.DefineMethod("FindGroupIndexDelegate", MethodAttributes.Public
                    | MethodAttributes.Static | MethodAttributes.HideBySig, CallingConventions.Standard,
                    typeof(int), new Type[] { typeof(int) });
                var methodIL = dynamicMethod.GetILGenerator();
                GenerateFindGroupIndexDelegate(methodIL, groupDataArray, 0, groupDataArray.Length - 1);
                Type t = typeBuilder.CreateType();
                MethodInfo method = t.GetMethod("FindGroupIndexDelegate");
                return (FindGroupIndexDelegate)Delegate.CreateDelegate(typeof(FindGroupIndexDelegate), method);
            }
            public static void GenerateFindGroupIndexDelegate<TValue>(ILGenerator methodIL,GroupData<TValue>[] groupDataArray, int left, int right)
            {
                int middle = (right + left + 1) >> 1;
                int lessThanValue = groupDataArray[middle].length;
                var elseStatement =  methodIL.DefineLabel();
                methodIL.Emit(OpCodes.Ldarg_0);
                methodIL.Emit(OpCodes.Ldc_I4,lessThanValue);
                methodIL.Emit(OpCodes.Bge_S, elseStatement);
                //if
                if (middle == left + 1)
                {
                    methodIL.Emit(OpCodes.Ldc_I4, left);
                    methodIL.Emit(OpCodes.Ret);
                }
                else
                {
                    GenerateFindGroupIndexDelegate(methodIL, groupDataArray, left, middle - 1);
                }
                //else
                methodIL.MarkLabel(elseStatement);
                if (middle == right)
                {
                    methodIL.Emit(OpCodes.Ldc_I4, right);
                    methodIL.Emit(OpCodes.Ret);
                }
                else
                {
                    GenerateFindGroupIndexDelegate(methodIL,groupDataArray,middle,right);
                }
            }
        }

    FindGroupIndexDelegate的Emit代码为:

        public class FastFindSameLengthStringHelper
        {
            public class Node
            {
                /// <summary>
                /// 对比的数字
                /// </summary>
                public long compareValue;
                /// <summary>
                /// if 语句节点
                /// </summary>
                public Node ifCase;
                /// <summary>
                /// else语句节点
                /// </summary>
                public Node elseCase;
                /// <summary>
                /// 节点的类型
                /// </summary>
                public NodeType nodeType;
                /// <summary>
                /// 对比的列数
                /// </summary>
                public int charIndex;
                /// <summary>
                /// 当只有一个元素时,返回该元素的索引
                /// </summary>
                public int arrayIndex;
            }
            public enum NodeType
            {
                CompareCreaterThan,
                CompareLessThan,
                SetIndex
            }
            public struct ColumnCompareData
            {
                public int[] ColumnSort;
                public bool hasMidValue;
                public long midValue;
                public int midValueIndex;
                public int midIndex;
                public LongCompare compare;
                public int[] ColumnBig;
                public int[] ColumnSmall;
                public int midDistance;
            }
            public enum LongCompare
            {
                LessThan,
                CreaterThan
            }
            public unsafe static FindDelegate GetFastFindSameLengthStringDelegate<TValue>(List<KV<TValue>> list, int length)
            {
                int rowCount = list.Count;
                int columnLength = (length + 3) >> 2;
                long[][] KeyLongArray = new long[rowCount][];
                for (int row = 0; row < rowCount; row++)
                {
                    fixed (char* pKey = list[row].key)
                    {
                        KeyLongArray[row] = new long[columnLength];
                        for (int col = 0; col < columnLength; col++)
                        {
                            if (col == columnLength - 1)
                            {
                                int remain = length & 3;
                                if (remain == 0)
                                {
                                    KeyLongArray[row][col] = *(long*)(pKey + col * 4);
                                }
                                else if (remain == 1)
                                {
                                    KeyLongArray[row][col] = *(short*)(pKey + col * 4);
                                }
                                else if (remain == 2)
                                {
                                    KeyLongArray[row][col] = *(int*)(pKey + col * 4);
                                }
                                else if (remain == 3)
                                {
                                    KeyLongArray[row][col] = *(long*)(pKey + col * 4 - 1);
                                }
                            }
                            else
                            {
                                KeyLongArray[row][col] = *(long*)(pKey + col * 4);
                            }
                        }
                    }
                }
                // 列排序索引,用于对Long二维数组列进行排序
                int[][] ColumnSortArray = new int[columnLength][];
                //初始化列索引数组
                for (int column = 0; column < columnLength; column++)
                {
                    ColumnSortArray[column] = new int[rowCount];
                    for (int row = 0; row < rowCount; row++)
                    {
                        ColumnSortArray[column][row] = row;
                    }
                }
                Node rootNode = new Node();
                Init(KeyLongArray,KeyLongArray,columnLength, ColumnSortArray, ref rootNode);
                ILWriter iLWriter = new ILWriter();
                return iLWriter.Generate(rootNode, length, columnLength);
            }
            public static void Init(long[][] FullKeyLongArray, long[][] KeyLongArray,int columnLength, int[][] ColumnSortArray, ref Node codeNode)
            {
                if (KeyLongArray == null) return;
                if (FullKeyLongArray.Length == 1)
                {
                    codeNode.nodeType = NodeType.SetIndex;
                    codeNode.arrayIndex = 0;
                    return;
                }
                // KeyValue数组长度
                int arrayLength = KeyLongArray.Length;
                //是否为奇数数组
                bool isEvenArray = (arrayLength & 1) == 0;
                //找到的最好中分的那个列
                int BestColumnCompareDataIndex = 0;
                //数组为奇数长度时,最中间的索引值
                int midIndex = 0;
                //数组为偶数长度时,中间左右两边的值
                int midLeftIndex, midRightIndex = 0;
                //距中间值的距离
                int midDistance = 0;
                //距中间值的最长距离
                int midDistanceLength = 0;
                //是否具有中间值,如果一个列中所有元素均相同,则无中间值
                bool hasMidValue = false;
                //是否找到了直接二分值
                bool hasFindBestColumnCompareDataIndex = false;
                //数组中每列比较的结果
                ColumnCompareData[] columnCompareData = new ColumnCompareData[columnLength]; ;
                //一列一列的解析出比较结果,如二分值,索引等
                for (int column = 0; column < columnLength; column++)
                {
                    //对列索引数组进行排序
                    Array.Sort<int>(ColumnSortArray[column], new KeyLongArrayCompare(FullKeyLongArray, column));
                    //是否有二分值
                    hasMidValue = false;
                    //如果数组长度为偶数
                    if (isEvenArray)
                    {
                        //中间距两边的距离
                        midDistanceLength = arrayLength >> 1;
                        //中间靠左边的索引值
                        midLeftIndex = (arrayLength >> 1) - 1;
                        //中间靠右边的索引值
                        midRightIndex = midLeftIndex + 1;
                        //找到与中间值值不同的行,并记录下来。
                        long LeftValue = GetKeyLong(FullKeyLongArray, ColumnSortArray[column][midLeftIndex], column);
                        long RightValue = GetKeyLong(FullKeyLongArray, ColumnSortArray[column][midRightIndex], column);
                        //[1][2][3][4]
                        //[1][Left]|[Right][4]
                        if (LeftValue != RightValue)
                        {
                            BestColumnCompareDataIndex = column;
                            hasFindBestColumnCompareDataIndex = true;
                            hasMidValue = true;
                            columnCompareData[column].hasMidValue = hasMidValue;
                            columnCompareData[column].midValue = RightValue;
                            columnCompareData[column].midValueIndex = ColumnSortArray[column][midRightIndex];
                            columnCompareData[column].compare = LongCompare.LessThan;
                            columnCompareData[column].midIndex = midRightIndex;
                            columnCompareData[column].midDistance = 0;
                            break;
                        }
                        else
                        {
                            //[1][2][3][4]
                            for (midDistance = 1; midDistance < midDistanceLength; midDistance++)
                            {
                                //[1]|[Left][3][4],2
                                if (LeftValue != GetKeyLong(FullKeyLongArray, ColumnSortArray[column][midLeftIndex - midDistance], column))
                                {
                                    hasMidValue = true;
                                    columnCompareData[column].hasMidValue = hasMidValue;
                                    columnCompareData[column].midValue = LeftValue;
                                    columnCompareData[column].midValueIndex = ColumnSortArray[column][midLeftIndex];
                                    columnCompareData[column].compare = LongCompare.LessThan;
                                    columnCompareData[column].midIndex = midLeftIndex;
                                    columnCompareData[column].midDistance = midDistance;
                                }
                                //[1][2][Right]|[4]
                                if (RightValue != GetKeyLong(FullKeyLongArray, ColumnSortArray[column][midRightIndex + midDistance], column))
                                {
                                    hasMidValue = true;
                                    columnCompareData[column].hasMidValue = hasMidValue;
                                    columnCompareData[column].midValue = RightValue;
                                    columnCompareData[column].midValueIndex = ColumnSortArray[column][midRightIndex];
                                    columnCompareData[column].compare = LongCompare.CreaterThan;
                                    columnCompareData[column].midIndex = midRightIndex;
                                    columnCompareData[column].midDistance = midDistance;
                                }
                            }
                        }
                    }
                    //如果数组长度为奇数
                    else
                    {
                        //中间到两边的距离
                        midDistanceLength = arrayLength >> 1;
                        //中间值的索引
                        midIndex = (arrayLength >> 1);
                        //找出与中间值不同的行
                        //[1][2][mid][3][4]
                        long midValue = GetKeyLong(FullKeyLongArray, ColumnSortArray[column][midIndex], column);
                        for (midDistance = 0; midDistance < midDistanceLength; midDistance++)
                        {
                            //[1][2]|[mid][3][4]
                            if (midValue != GetKeyLong(FullKeyLongArray, ColumnSortArray[column][midIndex - midDistance - 1], column))
                            {
                                hasMidValue = true;
                                columnCompareData[column].hasMidValue = hasMidValue;
                                columnCompareData[column].midValue = midValue;
                                columnCompareData[column].midValueIndex = ColumnSortArray[column][midIndex - midDistance - 1];
                                columnCompareData[column].compare = LongCompare.LessThan;
                                columnCompareData[column].midIndex = midIndex;
                                columnCompareData[column].midDistance = midDistance;
                                if (midDistance == 0)
                                {
                                    BestColumnCompareDataIndex = column;
                                    hasFindBestColumnCompareDataIndex = true;
                                    break;
                                }
                            }
                            //[1][2][mid]|[3][4]
                            if (midValue != GetKeyLong(FullKeyLongArray, ColumnSortArray[column][midIndex + midDistance + 1], column))
                            {
                                hasMidValue = true;
                                columnCompareData[column].hasMidValue = hasMidValue;
                                columnCompareData[column].midValue = midValue;
                                columnCompareData[column].compare = LongCompare.CreaterThan;
                                columnCompareData[column].midValueIndex = ColumnSortArray[column][midIndex + midDistance + 1];
                                columnCompareData[column].midIndex = midIndex;
                                columnCompareData[column].midDistance = midDistance;
                                if (midDistance == 0)
                                {
                                    BestColumnCompareDataIndex = column;
                                    hasFindBestColumnCompareDataIndex = true;
                                    break;
                                }
                            }
                        }
                    }
                }
                //如果没有直接找到了二分索引
                if (!hasFindBestColumnCompareDataIndex)
                {
                    //距离中间最小的距离
                    int minMidDistance = midDistanceLength;
                    //找到最合适的二分索引,即距两边距离最短的
                    for (int column = 0; column < columnLength; column++)
                    {
                        if (columnCompareData[column].midDistance < minMidDistance)
                        {
                            minMidDistance = columnCompareData[column].midDistance;
                            BestColumnCompareDataIndex = column;
                        }
                    }
                }
                //两个数组Big和Small
                long[][] KeyLongArrayBig = null;
                long[][] KeyLongArraySmall = null;
                int[][] ColumnSortArrayBig = null;
                int[][] ColumnSortArraySmall = null;
                int KeyLongArrayBigLength = 0;
                int KeyLongArraySmallLength = 0;
                //[1][2][midValue]|[3][4]
                if (columnCompareData[BestColumnCompareDataIndex].compare == LongCompare.CreaterThan)
                {
                    KeyLongArraySmallLength = columnCompareData[BestColumnCompareDataIndex].midIndex + 1;
                    if (KeyLongArraySmallLength > 0)
                    {
                        KeyLongArraySmall = new long[KeyLongArraySmallLength][];
                        //初始化排序数组
                        ColumnSortArraySmall = new int[columnLength][];
                        for (int column = 0; column < columnLength; column++)
                        {
                            ColumnSortArraySmall[column] = new int[KeyLongArraySmallLength];
                        }
                    }
                    KeyLongArrayBigLength = arrayLength - columnCompareData[BestColumnCompareDataIndex].midIndex - 1;
                    if (KeyLongArrayBigLength > 0)
                    {
                        KeyLongArrayBig = new long[KeyLongArrayBigLength][];
                        ColumnSortArrayBig = new int[columnLength][];
                        for (int column = 0; column < columnLength; column++)
                        {
                            ColumnSortArrayBig[column] = new int[KeyLongArrayBigLength];
                        }
                    }
                    int smallIndex = 0;
                    int bigIndex = 0;
                    for (int row = 0; row < arrayLength; row++)
                    {
                        if (row > columnCompareData[BestColumnCompareDataIndex].midIndex)
                        {
                            KeyLongArrayBig[bigIndex] = FullKeyLongArray[ColumnSortArray[BestColumnCompareDataIndex][row]];
                            for (int column = 0; column < columnLength; column++)
                            {
                                ColumnSortArrayBig[column][bigIndex] = ColumnSortArray[BestColumnCompareDataIndex][row];
                            }
                            bigIndex++;
                        }
                        else
                        {
                            KeyLongArraySmall[smallIndex] = FullKeyLongArray[ColumnSortArray[BestColumnCompareDataIndex][row]];
                            for (int column = 0; column < columnLength; column++)
                            {
                                ColumnSortArraySmall[column][smallIndex] = ColumnSortArray[BestColumnCompareDataIndex][row];
                            }
                            smallIndex++;
                        }
                    }
                }
                //[1][2]|[midValue][3][4]
                else if (columnCompareData[BestColumnCompareDataIndex].compare == LongCompare.LessThan)
                {
                    KeyLongArraySmallLength = columnCompareData[BestColumnCompareDataIndex].midIndex;
                    if (KeyLongArraySmallLength > 0)
                    {
                        KeyLongArraySmall = new long[KeyLongArraySmallLength][];
                        ColumnSortArraySmall = new int[columnLength][];
                        for (int column = 0; column < columnLength; column++)
                        {
                            ColumnSortArraySmall[column] = new int[KeyLongArraySmallLength];
                        }
                    }
                    KeyLongArrayBigLength = arrayLength - columnCompareData[BestColumnCompareDataIndex].midIndex;
                    if (KeyLongArrayBigLength > 0)
                    {
                        KeyLongArrayBig = new long[KeyLongArrayBigLength][];
                        ColumnSortArrayBig = new int[columnLength][];
                        for (int column = 0; column < columnLength; column++)
                        {
                            ColumnSortArrayBig[column] = new int[KeyLongArrayBigLength];
                        }
                    }
                    int smallIndex = 0;
                    int bigIndex = 0;
                    for (int row = 0; row < arrayLength; row++)
                    {
                        if (row < columnCompareData[BestColumnCompareDataIndex].midIndex)
                        {
                            KeyLongArraySmall[smallIndex] = FullKeyLongArray[ColumnSortArray[BestColumnCompareDataIndex][row]];
                            for (int column = 0; column < columnLength; column++)
                            {
                                ColumnSortArraySmall[column][smallIndex] = ColumnSortArray[BestColumnCompareDataIndex][row];
                            }
                            smallIndex++;
                        }
                        else
                        {
                            KeyLongArrayBig[bigIndex] = FullKeyLongArray[ColumnSortArray[BestColumnCompareDataIndex][row]];
                            for (int column = 0; column < columnLength; column++)
                            {
                                ColumnSortArrayBig[column][bigIndex] = ColumnSortArray[BestColumnCompareDataIndex][row];
                            }
                            bigIndex++;
                        }
                    }
                }
                //解析最终结果到CodeNode节点中,用于生成代码用
                if (columnCompareData[BestColumnCompareDataIndex].compare == LongCompare.CreaterThan)
                {
                    codeNode.nodeType = NodeType.CompareCreaterThan;
                    codeNode.compareValue = columnCompareData[BestColumnCompareDataIndex].midValue;
                }
                if(columnCompareData[BestColumnCompareDataIndex].compare==LongCompare.LessThan)
                {
                    codeNode.nodeType = NodeType.CompareLessThan;
                    codeNode.compareValue = columnCompareData[BestColumnCompareDataIndex].midValue;
                }
                //codeNode.ifCase = new Node();
                //codeNode.elseCase = new Node();
                codeNode.charIndex = BestColumnCompareDataIndex << 2;
                //[1][2][mid]|[4] if(x>mid){ i=3}else{i=4}
                //[1][2][mid]|[4][5]
                if (codeNode.nodeType == NodeType.CompareCreaterThan)
                {
                    if (KeyLongArrayBigLength == 0)
                    {
                        codeNode.ifCase = null;
                    }
                    else
                    {
                        codeNode = new Node();
                    }
                    if (KeyLongArrayBigLength == 1)
                    {
                        codeNode.ifCase.nodeType = NodeType.SetIndex;
                        codeNode.ifCase.arrayIndex = ColumnSortArray[BestColumnCompareDataIndex][columnCompareData[BestColumnCompareDataIndex].midIndex + 1];
                        codeNode.ifCase.charIndex = codeNode.charIndex;
                    }
                    else
                    {
                        Init(FullKeyLongArray, KeyLongArrayBig,columnLength, ColumnSortArrayBig, ref codeNode.ifCase);
                    }
                    if (KeyLongArraySmallLength == 0)
                    {
                        codeNode.elseCase = null;
                    }
                    else
                    {
                        codeNode.elseCase = new Node();
                    }
                    if (KeyLongArraySmallLength == 1)
                    {
                        codeNode.elseCase.nodeType = NodeType.SetIndex;
                        codeNode.elseCase.arrayIndex = ColumnSortArray[BestColumnCompareDataIndex][columnCompareData[BestColumnCompareDataIndex].midIndex];
                        codeNode.elseCase.charIndex = codeNode.charIndex;
    
                    }
                    else
                    {
                        Init(FullKeyLongArray, KeyLongArraySmall,columnLength, ColumnSortArraySmall, ref codeNode.elseCase);
                    }
                }
                //[1][2]|[mid][4][5] if(x<mid){}else{}
                else if (codeNode.nodeType == NodeType.CompareLessThan)
                {
                    if (KeyLongArraySmallLength == 0)
                    {
                        codeNode.ifCase = null;
                    }
                    else
                    {
                        codeNode.ifCase = new Node();
                    }
                    if (KeyLongArraySmallLength == 1)
                    {
                        codeNode.ifCase.nodeType = NodeType.SetIndex;
                        codeNode.ifCase.arrayIndex = ColumnSortArray[BestColumnCompareDataIndex][columnCompareData[BestColumnCompareDataIndex].midIndex - 1];
                        codeNode.ifCase.charIndex = codeNode.charIndex;
                    }
                    else
                    {
                        Init(FullKeyLongArray, KeyLongArraySmall,columnLength, ColumnSortArraySmall, ref codeNode.ifCase);
                    }
                    if (KeyLongArrayBigLength == 0)
                    {
                        codeNode.elseCase = null;
                    }
                    else
                    {
                        codeNode.elseCase = new Node();
                    }
                    if (KeyLongArrayBigLength == 1)
                    {
                        codeNode.elseCase.nodeType = NodeType.SetIndex;
                        codeNode.elseCase.arrayIndex = ColumnSortArray[BestColumnCompareDataIndex][columnCompareData[BestColumnCompareDataIndex].midIndex];
                        codeNode.elseCase.charIndex = codeNode.charIndex;
                    }
                    else
                    {
                        Init(FullKeyLongArray, KeyLongArrayBig,columnLength, ColumnSortArrayBig, ref codeNode.elseCase);
                    }
                }
            }
            public static long GetKeyLong(long[][] KeyLongArray, int RowIndex, int ColumnIndex)
            {
                if (ColumnIndex < KeyLongArray[RowIndex].Length)
                {
                    return KeyLongArray[RowIndex][ColumnIndex];
                }
                else
                {
                    return 0;
                }
            }
        }

    其运行效率如下:

    查询效率基本是传统字典的2倍以上。而且数量越多。字符串越长,其查询效率越高。

    NFinal2开源框架。https://git.oschina.net/LucasDot/NFinal2/tree/master qq:348764327.
  • 相关阅读:
    初学python 遇到的坑
    golang 裸写一个pool池控制协程的大小
    自制C#版3DS文件的解析器并用SharpGL显示3DS模型
    [译+改]最长回文子串(Longest Palindromic Substring) Part II
    [译]最长回文子串(Longest Palindromic Substring) Part I
    [我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之纹理Textures
    [我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之网格Meshes
    [我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之网格渲染器和过滤器Mesh renderers and filters
    [我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之材质了解Materials
    [我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之灯光介绍Lights
  • 原文地址:https://www.cnblogs.com/LucasDot/p/6693901.html
Copyright © 2020-2023  润新知