zoukankan      html  css  js  c++  java
  • 查找与排序02,折半查找

    折半查找,也叫二分查找,当在一个数组或集合中查找某个元素时,先定位出中间位置元素,如果要查找的元素正好和该中间位置元素相等,通过一次查找,就能找到匹配元素;如果要查找的元素小于该中间位置元素,就抛弃后面一半的元素,在前面一半的元素中再定位出中间位置元素,如此反复,直到找到匹配元素;如果要查找的元素大于该中间位置元素,就抛弃前面一半的元素,在后面一半的元素中定位出中间位置元素,如此反复。

    面临的第一个问题是:中间位置元素如何定位?在折半查找中规定:当元素个数是奇数,比如有3个元素,中间位置元素是索引为1的元素;当元素个数是偶数,比如有4个元素,索引为1和2的元素理论都是中间位置元素,但在折半查找中,把后面这个,即索引为2的元素视为中间位置元素。

    面临的第二个问题是:由于,要查找的元素和中间位置元素之间需要比较,我们在比较之前,势必要让数组按升序或降序来排列。

    自定义一个类,该类维护着一个int[]类型数组,通过构造函数确定数组长度和对数组进行排序,并提供打印数组元素的方法,以及折半算法。

        public class MyArray
    
        {
    
            private int[] arr;//内部维护着一个数组
    
            private static Random r = new Random();//用它来生成数组的随机元素
    
            //通过构造函数来确定内部数组的长度,并生成数组的随机元素,并对数组元素排序
    
            public MyArray(int size)
    
            {
    
                arr = new int[size];
    
                for (int i = 0; i < size; i++)
    
                {
    
                    arr[i] = r.Next(1, 100);
    
                }
    
                Array.Sort(arr);
    
            }
    
            //折半查找算法 返回查找元素的索引位置
    
            public int HalfSearch(int key)
    
            {
    
                int low = 0;//低点,初始值设置成最低点,即索引0
    
                int high = arr.Length - 1;//高点,初始值设置成最高点,即索引数组最后一个位置
    
                //如果数组元素个数是偶数,比如4个,索引2和3都是中间位置,用以下算法中间位置指向索引3
    
                //如果数组元素个数是奇数,比如3个,索引1是中间位置,用以下算法中间位置指向索引1
    
                int middle = (low + high + 1)/2;
    
                int location = -1;//找不到就返回-1
    
                //循环,找不到就一直查找
    
                do
    
                {
    
                    //每次循环,把低点和高点位置的元素打印出来
    
                    Console.WriteLine(PrintSectionElements(low, high));
    
                    Console.WriteLine();
    
                    //如果要查找元素是中间位置的元素,就返回中间位置这个索引
    
                    if (key == arr[middle])
    
                    {
    
                        location = middle;
    
                    }
    
                    else if (key < arr[middle]) //如果要查找元素小于中间位置元素,把中间位置前面的索引设为高点
    
                    {
    
                        high = middle - 1;
    
                    }
    
                    else//如果要查找元素大于中间位置元素,把中间位置后面的索引设为低点
    
                    {
    
                        low = middle + 1;
    
                    }
    
                    //如果代码运行到此处,说明还没有找到匹配元素,由于以上重新设置了低点或高点,所以这里也要重新设置中间位置
    
                    middle = (low + high + 1)/2;
    
                } while ((low <= high) && (location == -1));
    
                return location;
    
            }
    
            //打印2个位置间的数组元素
    
            public string PrintSectionElements(int low, int high)
    
            {
    
                string temp = "";
    
                //对于2个位置间的元素打印出元素并跟上一个空格位置
    
                for (int i = low; i <= high; i++)
    
                {
    
                    temp += arr[i] + " ";
    
                }
    
                return temp;
    
            }
    
            //重写ToString方法,把数组所有的元素都打印出来
    
            public override string ToString()
    
            {
    
                return PrintSectionElements(0, arr.Length - 1);
    
            }
    
        }
    

    以上,折半查找的目的是找到匹配元素在数组中的索引位置,为此,通过需查找元素和中间位置元素大小的比较,不断地调整低点、高点和中间位置。另外,在C#中,1/2的结果是0。

    客户端。

        class Program
    
        {
    
            private static int key; //需查找元素
    
            private static int position;//匹配元素所在的位置
    
            static void Main(string[] args)
    
            {
    
                MyArray myArray = new MyArray(7);
    
                //把所有元素打印出来
    
                Console.WriteLine(myArray);
    
                Console.WriteLine("请输入需要查找的元素或输入-1退出 ");
    
                key = Convert.ToInt32(Console.ReadLine());
    
                Console.WriteLine();
    
                while (key != -1)
    
                {
    
                    //调用折半算法得出所需查找元素的位置
    
                    position = myArray.HalfSearch(key);
    
                    if (position == -1) //说明没有找到需要匹配的元素
    
                    {
    
                        Console.WriteLine("没有找到元素{0}", key);
    
                    }
    
                    else
    
                    {
    
                        Console.WriteLine("在{0}号位置查到元素{1}", position, key);
    
                    }
    
                    Console.WriteLine("请输入需要查找的元素或输入-1退出 ");
    
                    key = Convert.ToInt32(Console.ReadLine());
    
                    Console.WriteLine();
    
                }
    
            }
    
        }
    

    1

      用时间复杂度来描述折半查找的效率

    假设一个数组有1023个元素,由于可以表示成"1023=2ⁿ-1"等式,所有n=10。对该数组每进行一次折半,相当于除以2,也就是说,在该数组中查找某个元素,最多需要10次,就可以查到匹配元素。

    对于"2ⁿ-1"这个表达式,当n=30,就表示10亿,使用折半查找,10亿个元素最多需要30次就能找到匹配元素。而使用线性查找需要平均5亿次的查找。2种算法的效率由此可见一斑。

    把折半查找、二分查找的时间复杂度写成O(log n),称为"对数运行时间",读为"对数阶"。

    “查找与排序”系列包括:

    查找与排序01,线性查找,时间复杂度,算法

    查找与排序02,折半查找

    查找与排序03,选择排序

    查找与排序04,插入排序

    查找与排序05,冒泡排序

  • 相关阅读:
    Validation failed for one or more entities. See 'EntityValidationErrors' property for more details
    Visual Studio断点调试, 无法监视变量, 提示无法计算表达式
    ASP.NET MVC中MaxLength特性设置无效
    项目从.NET 4.5迁移到.NET 4.0遇到的问题
    发布网站时应该把debug设置false
    什么时候用var关键字
    扩展方法略好于帮助方法
    在基类构造器中调用虚方法需谨慎
    ASP.NET MVC中商品模块小样
    ASP.NET MVC中实现属性和属性值的组合,即笛卡尔乘积02, 在界面实现
  • 原文地址:https://www.cnblogs.com/darrenji/p/3873672.html
Copyright © 2011-2022 走看看