• 查找


    查找的算法主要有几种:二分查找,插入查找,斐波那契查找。注:所有的查找算法都是在有序数组中

    二分查找:顾名思义,先从中间值开始查找,然后不断逼近,类似高中的二分法

    二分查找完整代码如下:

    public static int BinarySearch(int[] arr, int left, int right, int value)
            {
                if (left == right)
                {
                    return -1;
                }
                int mid = (left + right) / 2;
                int midVal = arr[mid];
                if (value > midVal)
                {
                    return BinarySearch(arr, mid + 1, right, value);
                }
                else if (value < midVal)
                {
                    return BinarySearch(arr, left, mid - 1, value);
                }
                else
                {
                    return mid;
                }
            }

    二分查找还有个改进算法,可以找到重复的元素,代码如下:

    public static List<int> BinarySearch2(int[] arr, int left, int right, int value)
            {
                if (left == right)
                {
                    return new List<int>();
                }
                int mid = (left + right) / 2;
                int midVal = arr[mid];
                if (value > midVal)
                {
                    return BinarySearch2(arr, mid + 1, right, value);
                }
                else if (value < midVal)
                {
                    return BinarySearch2(arr, left, mid - 1, value);
                }
                else
                {
                    List<int> list = new List<int>();
                    list.Add(mid);
                    int temp = mid - 1;
                    while (true)
                    {
                        //因为二分查找为有序数组 所以在arr[temp]!=value时之间跳出循环
                        if (temp < 0 || arr[temp] != value)
                        {
                            break;
                        }
                        list.Add(temp);
                        temp -= 1;
                    }
                    temp = mid + 1;
                    while (true)
                    {
                        if (temp > arr.Length - 1 || arr[temp] != value)
                        {
                            break;
                        }
                        list.Add(temp);
                        temp += 1;
                    }
                    return list;
                }
            }

    插入查找也可以认为是二分查找的改进,其改进之处在于插入查找插入点不再是中点,而是随着查找值改变(自适应查找)

    插入查找适用于均匀分布的数组,原因很简单 其本质是等比例缩放法 value/mid=arr[右]-arr[左]/arr.Length

    插入查找完整代码如下:

     1 public static int InsertSearch(int[] arr, int left, int right, int value)
     2         {
     3             if (left > right || value < arr[0] || value > arr[arr.Length - 1])
     4             {
     5                 return -1;
     6             }
     7             int mid = left + (right - left) * (value - arr[left]) / (arr[right] - arr[left]);
     8             int midVal = arr[mid];
     9             if (value > midVal)
    10             {
    11                 return InsertSearch(arr, mid + 1, right, value);
    12             }
    13             else if (value < midVal)
    14             {
    15                 return InsertSearch(arr, left, mid - 1, value);
    16             }
    17             else
    18             {
    19                 return mid;
    20             }
    21         }

    斐波那契查找本质也和二分查找类似,其插入点是接近黄金分割点(虽然不知道有什么意义,但人家这么搞跟着搞就对了^^)

    完整代码如下:

     1  //构建斐波那契数列
     2         public static int[] fib()
     3         {
     4             int[] f = new int[20];
     5             f[0] = 1;
     6             f[1] = 1;
     7             for (int i = 2; i < f.Length; i++)
     8             {
     9                 f[i] = f[i - 1] + f[i - 2];
    10             }
    11             return f;
    12         }
    13 
    14         public static int fibSearch(int[] a, int key)
    15         {
    16             int low = 0;
    17             int high = a.Length - 1;
    18             int k = 0;//表示斐波那契分割数值的下标
    19             int mid = 0;//存放mid值
    20             int[] f = fib();
    21             //获取到斐波那契分割数值的下标
    22             while (high > f[k] - 1)
    23             {
    24                 k++;
    25             }
    26             //因为k值可能大于a长度 构建一个数组temp 将a的值全部放入temp 不足用0补
    27             int[] temp = new int[f[k]];
    28             a.CopyTo(temp, 0);
    29             //实际中用a最后的元素填充temp的0部分
    30             for (int i = high + 1; i < temp.Length; i++)
    31             {
    32                 temp[i] = a[high];
    33             }
    34             //用while循环处理 
    35             while (low <= high)
    36             {
    37                 mid = low + f[k - 1] - 1;
    38                 //如果要找到的值在左边
    39                 if (key < temp[mid])
    40                 {
    41                     high = mid - 1;
    42                     //f[k]=f[k-1]+f[k-2] 左边数组为f[k-1] 该数组斐波那契为f[k-1]=f[k-2]+f[k-3]
    43                     k--;
    44                 }
    45                 else if (key > temp[mid])//要找的值在右边
    46                 {
    47                     low = mid + 1;
    48                     k -= 2;
    49                 }
    50                 else //要找的值就是mid 因为是在temp中找的 可能长度大于a.length 所以返回小一点的
    51                 {
    52                     if (mid <= high)//没有超出a
    53                     {
    54                         return mid;
    55                     }
    56                     else//超出了a
    57                     {
    58                         return high;
    59                     }
    60                 }
    61             }
    62             //找不到 返回-1
    63             return -1;
    64         }
     
  • 相关阅读:
    DBCA创建数据库ORA-01034 ORACLE not available
    Linux shell 内部变量
    ext4文件系统制作
    curses-键盘编码-openssl加解密【转】
    Linux 中的键盘映射【转】
    C 语言 字符串命令 strstr()的用法 实现将原字符串以分割串分割输出【转】
    Linux下使用popen()执行shell命令【转】
    linux下获取按键响应事件【转】
    linux select函数:Linux下select函数的使用详解【转】
    OTA升级中关于update.zip包的一些总结【转】
  • 原文地址:https://www.cnblogs.com/TheLin/p/13893575.html
Copyright © 2020-2023  润新知