C#二分法

1.前提:使用二分法需要将数组先排序好
2.优势:在大数据集合中一次可过滤一半
3.使用:

3.1 方式1:普通遍历

        /// <summary>
        /// 遍历获取二分法查值索引
        /// </summary>
        /// <param name="students">集合:必须已排序好(此处以正序为例)</param>
        /// <param name="key">查找值</param>
        /// <returns></returns>
        public int GetEFF(int[] students,int key)
        {
            int left = 0;
            int right = students.Length;
            while (left <= right) //1.left大于right时需要退出
            {
                
                int avg = (left + right) / 2; //2.对半拆
                if (key > students[avg]) //3.查找值大于中间值则证明在集合右边,所以需要给left赋中间值加1(从中间值右侧第一个索引开始)
                {
                    left = avg + 1;
                }
                else if (key < students[avg]) //4.查找值小于中间值则证明在集合左边,所以需要给right赋中间值减1(从中间值左侧第一个索引开始)
                {
                    right = avg - 1;
                }
                else 
                {
                    return avg;
                }
            }
            return -1;
        }

3.2 方式2:递归遍历

        /// <summary>
        /// 递归二分法查值索引
        /// </summary>
        /// <param name="left">左索引</param>
        /// <param name="right">右索引</param>
        /// <param name="students">集合:必须已排序好(此处以正序为例)</param>
        /// <param name="key">查找值</param>
        /// <returns></returns>
        public int dgGetEFF(int left,int right, int[] students, int key)
        {
            if (left > right) //1.left大于right时需要退出
            {
                return -1;
            }
            else
            {
                int avg = (left + right) / 2; //2.对半拆
                if (key > students[avg]) //3.查找值大于中间值则证明在集合右边,所以需要给left赋中间值加1(从中间值右侧第一个索引开始)
                {
                   return dgGetEFF(left + 1, right, students, key);
                }
                else if (key < students[avg]) //4.查找值小于中间值则证明在集合左边,所以需要给right赋中间值减1(从中间值左侧第一个索引开始)
                {
                   return dgGetEFF(left, right - 1, students, key);
                }
                else
                {
                    return avg;
                }
            }
        }

4.数组存在重复元素

        /// <summary>
        /// 二分法获取指定元素索引集合
        /// </summary>
        /// <param name="source">集合:必须已排序好(此处以正序为例)</param>
        /// <param name="key">查找值</param>
        /// <returns></returns>
        public static List<int> GetEFFS(int[] source, int key)
        {
            //左索引
            int left = 0;
            //右索引
            int right = source.Length;
            //下标
            int mid = 0;
            //数组的中位值的索引值集合
            List<int> mids = new List<int>();

            while (left <= right) //1.left大于right时需要退出
            {

                mid = (left + right) / 2; //2.对半拆
                if (key > source[mid]) //3.查找值大于中间值则证明在集合右边,所以需要给left赋中间值加1(从中间值右侧第一个索引开始)
                {
                    left = mid + 1;
                }
                else if (key < source[mid]) //4.查找值小于中间值则证明在集合左边,所以需要给right赋中间值减1(从中间值左侧第一个索引开始)
                {
                    right = mid - 1;
                }
                else
                {
                    //因为已经排序好,找到所要查询的坐标以后,判断它左右是否与查询值一致,若一致,则添加下标
                    mids.Add(mid);
                    //进行左索引递归
                    Getindexs(source, mid, key, true, mids);
                    //进行右索引递归
                    Getindexs(source, mid, key, false, mids);
                    //递归结束返回所有重复索引值
                    return mids;
                }
            }
            return mids;
        }

        /// <summary>
        /// 递归获取mid左右元素等于key的下标值
        /// </summary>
        /// <param name="source">数组</param>
        /// <param name="mid">查询值下标</param>
        /// <param name="key">查询值</param>
        /// <param name="isLeft">往左还是往右递归</param>
        /// <param name="ids">相同元素下标集合</param>
        static void Getindexs(int[] source,int mid,int key, bool isLeft,List<int> ids)
        {
            if (isLeft)
            {
                int left = mid-1;
                if (source[left] != key)
                {
                    return;
                }
                else
                {
                    ids.Add(left);
                    Getindexs(source,left, key, true,ids);
                }
            }
            else
            {
                int right = mid+1;
                if (source[right] != key)
                {
                    return;
                }
                else
                {
                    ids.Add(right);
                    Getindexs(source, right, key, false, ids);
                }
            }
        }

5.二分法获取范围元素
5.1 方式1:找到最小值下标,后向右递归获取所有元素下标直到大于最大值退出

        /// <summary>
        /// 二分法获取指定元素范围索引集合
        /// </summary>
        /// <param name="source">集合</param>
        /// <param name="min">最小值</param>
        /// <param name="max">最大值</param>
        /// <returns></returns>
        private static List<int> GetWhereIndexs(double[] source, double min, double max)
        {
            //数组左边界索引值
            int left = 0;
            //数组的右边界索引值
            int right = source.Length;
            //数组的中位值的索引值集合
            int mid = 0;
            //范围元素下标集合
            List<int> mids = new List<int>(); ;

            //在循环中,根据中位值与目标值对比,更新左(右)边界的值,从而缩小检索范围,直到找到目标值。
            while (left <= right)
            {
                mid = (left + right) / 2; //2.对半拆
                if (min > source[mid]) //3.查找值大于中间值则证明在集合右边,所以需要给left赋中间值加1(从中间值右侧第一个索引开始)
                {
                    left = mid + 1;
                }
                else if (min < source[mid]) //4.查找值小于中间值则证明在集合左边,所以需要给right赋中间值减1(从中间值左侧第一个索引开始)
                {
                    right = mid - 1;
                }
                else
                {
                    //因为已经排序好,先找最小的min,找到后往右递归直到大于max时退出
                    mids.Add(mid);
                    //递归获取从最小值开始到最大值下标集合
                    GetMaxindexs(source,mid,min,max,mids);
                    //递归结束返回所有重复索引值
                    return mids;
                }
            }

            return mids;
        }

        /// <summary>
        /// 递归获取mid往右元素等于key的同时小于等于max的下标值
        /// </summary>
        /// <param name="source">数组</param>
        /// <param name="mid">查询值下标</param>
        /// <param name="min">查询值(最小值)</param>
        /// <param name="max">最大值</param>
        /// <param name="ids">相同元素下标集合</param>
        static void GetMaxindexs(double[] source, int mid, double min, double max, List<int> ids)
        {
            int left = mid + 1;
            if (source[left] > max)
            {
                return;
            }
            else
            {
                ids.Add(left);
                GetMaxindexs(source, left, min, max, ids);
            }
        }

5.2 方式2:找到最小值下标min,在找到最大值下标max,去除头尾就是我们想要的范围集合,即满足:
O(min) >= a <= O(max)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值