查找

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

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

二分查找完整代码如下:

 

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         }

 

 

 

posted @ 2020-10-28 21:21  这总没有了吧  阅读(133)  评论(0编辑  收藏  举报