二分查找的理解(java程序举例)

二分查找的解释

         二分查找又叫做折半查找,其作用有两个,一是可以高效的查询有序的数列中是否存在要查询的元素以及元素的位置,二是如果要往有序的数列中插入一个数,可以高效的查找到添加位置(但是由于其存储结构是顺序的,因此插入时效率低),由于其查找原理的好处使得二分查找的最坏情况的时间复杂度也为O(log2n),要优于顺序查找,其查找原理稍后用实例解释。

需要满足的条件

  1. 二分查找是针对大小有序的数列来说的,不管是从大到小还是从小到大
  2. 要查找的数据必须是一种顺序的存储结构

先看一个java实例

该例中我封装了一个二分查找的方法,进行了一次模拟调用,先尝试看懂代码,在程序运行截图后面我描述了整个运行过程,可以帮助理解,中间的输出语句是输出区间范围的,已经注释掉了。

public class Binary {
	public static void main(String[] args) {
		int arr[] = { 3, 7, 8, 11, 45, 56, 66, 68, 79, 82, 99 };
		Binary bi = new Binary();
		int location = bi.getLocation(66, arr);
		if (location > 0) {//location表示查找返回的位置,没有找到返回0
			System.out.println("该数出现在第" + location + "位置");
		} else {
			System.out.println("无此数");
		}
	}

	/**
	 * 该方法内封装了二分查找
	 * 
	 * @param data
	 *            传入一个int型数据
	 * @param arr
	 *            传入一个int型数组
	 * @return 返回元素位置,没查到返回0
	 */
	public int getLocation(int data, int arr[]) {
		// 采用二分查找每次都要缩小查找区间范围,begin是区间首位数字下标,end相反
		int begin = 0, end = arr.length - 1;
		// 用于记录 要查找数字存在的位置
		int location = 0;
		// 保证要查找的数字在该数组的区间范围内
		if (data >= arr[0] && data <= arr[arr.length - 1]){
			while (end - 1 > begin) {  //当区间元素相邻则退出循环 
				int mid = (begin + end) / 2;    //mid是取区间的中间数,与data比较之后可以缩小比较的区间范围
				if (data > arr[mid]) {
					begin = mid;  //在满足data比中间数大的时候,则把中间数下标赋值给begin,因此缩小了比较区间
					//System.out.println("中间值为"+mid+"     重新确定区间为" + arr[begin] + " " + arr[end]);
				} else if (data < arr[mid]) {
					end = mid;
					//System.out.println("中间值为"+mid+"     重新确定区间为" + arr[begin] + " " + arr[end]);
				} else {
					//System.out.println("中间值为"+mid);
					location = mid + 1;
					break;//当遇到相同元素记录该下标并强制退出循环
				}
			}
		}
		if(location==0){//上述循环完成后有可能漏掉begin和end下标表示的元素,因此在比较一下
			if (arr[begin] == data)
				location = begin + 1;
			if (arr[end] == data)
				location = end + 1;
		}
		return location;
	}
}

运行结果为

运行过程描述如下

       从截图可以看出,在进行二分查找的过程中,两次重新确定该值的区间,在 3, 7, 8, 11, 45, 56, 66, 68, 79, 82, 99中查找66

  1. 第一遍下标begin=0,end=10,mid=5,因此mid下标指示的数字是56,66>56因此区间改变,begin=mid=5
  2. 第二遍下标begin=5,end=10,mid=7,因此mid下标指示的数字是68,66<68因此区间改变,end=mid=7
  3. 第三遍下标begin=5,end=7,mid=6,因此mid下标指示的数字是66,因此确定了位置,循环强制退出

 

<think>好的,我现在需要回答用户关于Java集合框架的概念及用法的问题。用户可能刚开始学习Java,对集合框架不太了解,需要基础的解释。首先,我应该从集合框架的整体结构入手,因为用户提到“概念及用法”,可能需要先了解框架的组成部分,再深入到具体用法。 根据系统指令,我需要使用中文回答,并且正确应用LaTeX格式。比如,在提到集合框架的两大家族时,需要用$...$来包裹数学表达式或者术语吗?不过这里的集合框架名称可能不需要数学格式,但如果有类似List<E>这样的泛型,可能需要使用LaTeX。比如,List<E>可以写成$List<E>$,但不确定是否正确,可能需要保持原样,或者使用代码块。不过用户示例中的代码用了代码块,所以可能对于代码部分应该使用代码块,而术语如List、Set等则用普通文本。 接下来,我需要整合站内的引用内容。引用[3]提到Java集合框架的概念,引用[2]说明集合框架分为Collection和Map两大家族,引用[5]介绍了Set的用法和示例代码,引用[4]强调了集合框架的应用场景和线程安全的问题。引用[1]可能和示例中的快速排序无关,但用户的问题是关于集合框架的,所以可能需要忽略引用[1]。 首先,我应该定义Java集合框架,说明其作用,比如存储和操作对象。然后按照Collection和Map两大接口来分述,Collection下分为List、Set、Queue,而Map是键值对。需要给出每个接口的常用实现类,比如List的ArrayList、LinkedList,Set的HashSet、TreeSet,Map的HashMap、TreeMap等。 然后,用法部分可以举例说明,比如如何使用ArrayList添加元素,遍历,或者使用HashSet去重。引用[5]中的代码示例展示了HashSet的使用,可以引用这段代码并解释。同时,提到线程安全问题,如引用[4]中提到的,可以说明哪些集合是线程安全的,比如Vector、Hashtable,或者使用Collections.synchronizedList等方法。 另外,需要提到集合框架的适用场景,比如需要有序元素时用List,需要唯一性用Set,键值对存储用Map。这部分可以结合引用[4]的内容,说明不同集合的特点和选择依据。 在回答过程中,要确保结构清晰,分点说明概念、结构、用法、注意事项等。同时,按照系统指令生成相关问题,比如集合框架的组成、List和Set的区别、如何选择集合类型等。 需要检查是否有遗漏的部分,比如是否提到Queue接口,或者迭代器的使用,如引用[5]中的迭代器示例。此外,可能还需要提到Java集合框架的优势,如提供通用接口、算法等,提高开发效率。 最后,确保所有引用正确标注,例如在提到线程安全时引用[4],在讨论Set时引用[5]等。同时,生成的三个相关问题应该与集合框架相关,覆盖概念、区别和实际应用。</think>### Java集合框架概念及用法 #### 一、Java集合框架的核心概念 Java集合框架(Java Collections Framework)是为存储和操作对象组提供的一套标准化接口和实现类,包含数据结构(如列表、集合、队列、映射)和通用算法(如排序、搜索)[^3]。其核心设计目标是通过统一接口降低编程复杂度,同时保证高效性和灵活性[^4]。 #### 二、框架结构 Java集合框架分为两大分支: 1. **Collection家族**:存储单一对象,包含三个主要子接口: - **$List$**:有序且允许重复(如$ArrayList$、$LinkedList$) - **$Set$**:无序且元素唯一(如$HashSet$、$TreeSet$) - **$Queue$**:先进先出或优先级队列(如$PriorityQueue$)[^2] 2. **$Map$家族**:存储键值对(key-value pairs),键唯一(如$HashMap$、$TreeMap$)[^2] #### 三、常用实现类示例 1. **List的使用** ```java List<String> list = new ArrayList<>(); list.add("Java"); list.add("Python"); for (String s : list) { System.out.println(s); } ``` 2. **Set的去重特性** ```java Set<Integer> set = new HashSet<>(); set.add(1); set.add(1); // 重复元素不会被添加 System.out.println(set.size()); // 输出1 [^5] ``` 3. **Map的键值存储** ```java Map<String, Integer> scores = new HashMap<>(); scores.put("Alice", 90); System.out.println(scores.get("Alice")); // 输出90 ``` #### 四、关键注意事项 1. **线程安全性** 大部分集合类(如$ArrayList$、$HashMap$)**非线程安全**,多线程环境下需使用同步包装器: ```java List<String> syncList = Collections.synchronizedList(new ArrayList<>()); ``` 或选择线程安全实现类(如$ConcurrentHashMap$)。 2. **性能考量** - $ArrayList$:随机访问快($O(1)$),插入/删除慢($O(n)$) - $LinkedList$:插入/删除快($O(1)$),随机访问慢($O(n)$) - $HashSet$:查找/插入平均$O(1)$,但无序 - $TreeSet$:元素有序,操作时间复杂度$O(\log n)$ #### 五、选择集合的标准 - 需要唯一元素 → **$Set$** - 需要键值关联 → **$Map$** - 频繁随机访问 → **$ArrayList$** - 频繁插入删除 → **$LinkedList$** - 需要自然排序 → **$TreeSet$/$TreeMap$**
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值