java实现常见查找算法

电脑杂谈  发布时间:2019-06-18 13:09:45  来源:网络整理

树和二叉树的转换_c 二叉排序树_排序二叉树的删除

查找

查找(Searching)就是根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素(或记录)。

在互联网上查找信息是我们的家常便饭。所有这些需要被查的数据所在的集合,我们给它一个统称叫查找表。

查找表(Search Table)是由同一类型的数据元素(或记录)构成的集合。

关键字(Key)是数据元素中某个数据项的值,又称为键值,用它可以标识一个数据元素。也可以标识一个记录的某个数据项(字段) ,我们称为关键码。

若此关键字可以唯一地标识一个记录,则称此关键字为主关键字 (Primary Key)。

注意这也就意味着,对不同的记录,其主关键字均不相同。主关键字所在的数据项称为主关键码。

那么对于那些可以识别多个数据元素(或记录)的关键字,我们称为次关键字(Secondary Key)。次关键字也可以理解为是不以唯一标识一个数据元素(或记录)的关键字,它对应的数据项就是次关键码。

查找表按照操作方式来分有两大种:静态查找表和动态查找表。

静态查找表(Static Search Table) :只作查找操作的查找表。它的主要操作有:

( 1 ) 查询某个"特定的"数据元素是否在查找表中。

( 2 ) 检索某个"特定的"数据元索和各种属性。

按照我们大多数人的理解,查找,当然是在已经有的数据中找到我们需要的。静态查找就是在干这样的事情,不过,现实中还有存在这样的应用:查找的目的不仅仅只是查找,还可能边查找边作其它操作。

动态查找表(Dynamic Search Table): 在查找过程中同时插入查找表中不存在的数据元素,或者从查找表中删除已经存在的某个数据元素。显然动态查找表的操作就是两个:

( 1 ) 查找时插入数据元素。

( 2 ) 查找时删除数据元素。

为了提高查找的效率 ,我们需要专门为查找操作设置数据结构,这种面向查找操作的数据结构称为查找结构。

从逻辑上来说,查找所基于的数据结构是集合,集合中的记录之间没有本质关系。可是要想获得较高的查找性能,我们就不得不改变数据元素之间的关系,在存储时可以将查找集合组织成表、树等结构。

例如,对于静态查找表来说,我们不妨应用线性表结构来组织数据,这样可以使用顺序查找算法,如果再对主关键字排序,则可以应用折半查找等技术进行高效的查找。

如果是需要动态查找,则会复杂一些,可以考虑二叉排序树的查找技术。另外,还可以用散列表结构来解决一些查找问题,这些技术都将在后面的讲解中说明。

顺序查找 (Sequential Search) 又叫线性查找,是最基本的查找技术, 它的查找过程是:从表中第一个(或最后一个)记录开始,逐个进行记录的关键字和给定值比较,若某个记录的关键字和给定值相等,则查找成功,找到所查的记录;如果直到最后一个(或第一个)记录,其关键字和给定值比较都不等时,则表中没有所查的记录,查找不成功 。

顺序查找的算法实现如下。

/**
 * 顺序查找
 * 
 * @param a
 *            数组
 * @param key
 *            待查找关键字
 * @return 关键字下标
 */
public static int sequentialSearch(int[] a, int key) {
	for (int i = 0; i < a.length; i++) {
		if (a[i] == key)
			return i;
	}
	return -1;
}

这段代码非常简单,就是在数组a中查看有没有关键字key,当你需要查找复杂表结构的记录时,只需要把数组a与关键字key定义成你需要的表结构和数据类型即可。

到这里并非足够完美,因为每次循环时都需要对i是否越界,即是否小于等于n作判断。事实上,还可以有更好一点的办法,设置一个哨兵,可以解决不需要每次让i与n作比较。看下面的改进后的顺序查找算法代码。

/**
 * 有哨兵顺序查找
 * 
 * @param a
 *            数组(下标为0存放哨兵元素)
 * @param key
 *            待查询关键字
 * @return 关键字下标 返回0 则未找到
 */
public static int sequentialSearch2(int[] a, int key) {
	int index = a.length - 1;
	a[0] = key;// 将下标为0的数组元素设置为哨兵
	while (a[index] != key) {
		index--;
	}
	return index;
}

这种在查找方向的尽头放置"哨兵"免去了在查找过程中每一次比较后都要判断查找位置是否越界的小技巧,看似与原先差别不大,但在总数据较多时,效率提高很大,是非常好的编码技巧。当然,"哨兵"也不一定就一定要在数组开始,也可以在末端。

对于这种顺序查找算法来说,查找成功最好的情况就是在第一个位置就找到了,算法时间复杂度为O(1),最坏的情况是在最后一位置才找到,需要n次比较,时间复杂度为O(n),当查找不成功时,需要n+1次比较,时间复杂度为O(n)。我们之前推导过,关键字在任何一位置的概率是相同的,所以平均查找次数为(n+1)/2 ,所以最终时间复杂度还是O(n)。

很显然,顺序查找技术是有很大缺点的,n很大时,查找效率极为低下,不过优点也是有的,这个算法非常简单,对静态查找表的记录没有任何要求,在一些小型数据的查找时,是可以适用的。

后面的14 20其实是多余的,因为碰到的概率是千分之一,但是为了防止这种小概率事件的发生,所以把14 20可以带上,并不是说14 20中了就赚钱了,而是说,如果碰到这种错误周期集中的极端现象时,我们不要着急,因为概率决定了我们的命中率是10中7 所以,前面错的多,后面必然对的就多,不然是没法回归均衡的,后面既然对的多,那么14 或者20我们一直平买,很快就把前面亏的赚回来了,然后就可以回到1倍从新开始了,这个你只要实战操作几天就知道了。2、为什么要把2个放在3个的前面,4个放在3个的后面(2个比3个少1个,排在3个的前面,4个比3个多1个,排在4个的后面)。让宝宝将两手放在身体前面和后面,或把玩具放在身前身后,让孩子形成前后概念,然后扩大到日常生活中,“你看那棵树,是在房子前面,还是后面。

一个线性表有序时,对于查找总是很有帮助的。

折半查找(Binary Search)技术,又称为二分查找。它的前提是线性表中的记录必须是关键码有序(通常从小到大有序) ,线性表必须采用顺序存储。折半查找的基本思想是:在有序表中,取中间记录作为比较对象,若给定值与中间记录的关键字相等,则查找成功;若给定值小于中间记录的关键字,则在中间记录的左半区继续查找;若给定值大于中间记录的关键字,则在中间记录的右半区继续查找。不断重复上 述过程,直到查找成功,或所有查找区域无记录,查找失败为止。

我们来看折半查找的算法是如何工作的。

/**
 * 折半查找
 * 
 * @param a
 *            数组
 * @param key
 *            待查找关键字
 * @return 返回折半下标, -1表示不存在该关键字
 */
public static int binarySearch(int[] a, int key) {
	int low, mid, high;
	low = 0;// 最小下标
	high = a.length - 1;// 最大小标
	while (low <= high) {
		mid = (high + low) / 2;// 折半下标
		if (key > a[mid]) {
			low = mid + 1; // 关键字比 折半值 大,则最小下标 调成 折半下标的下一位
		} else if (key < a[mid]) {
			high = mid - 1;// 关键字比 折半值 小,则最大下标 调成 折半下标的前一位
		} else {
			return mid; // 当 key == a[mid] 返回 折半下标
		}
	}
	return -1;
}

针对异构环境 中的效率 0.85 023 o.24 o.42调度这一复杂 问题,以fork.join这类特殊而重要 的任务图为时间复杂度 df1 d v1 df 0 vlog们研究对象,本文提 出一个具有高的加速 比的贪心调度算法一tds算法将join任务 的每个父任务分别调度至不 同处理 htgsfj算法,该算法借鉴同构环境经典算法 的相关策略,同机 ,不仅可能失去生成较短调度的机会 ,而且忽视 了异构环境 时又充分考虑异构环境的特点,可 以应用至任意 fork.join任的特点,使得调度长度很长、处理机个数很多,共使用 了5个 务 图并产生有效的调度 ,其时间复杂度为d v2 ,其 中,v表示任处理机 。纯属复习或者说再学一遍tarjan算法,本题的主要算法就是tarjan+缩点,对于两个子问题的答案,根据解题:强连通缩点为拓扑图后,设入度为0点数为r,出度为0点数为c,则task 1的答案就是r,这个很好理解。arm和x86功耗的差别一直是个很热的话题.arm可以做的很低,甚至1瓦都不到.而x86服务器的芯片可以达到100-200瓦,就算是嵌入式处理器 atom系列也需要几瓦.很说这是指令集的关系.arm采用精简指令集,x86采用复杂指令集,前者每条功能简单,单挑指令耗电低.而后者每条指令复 杂,单个指令耗电高.但是这种解释很模糊.如果大家都做同样的事情,完成一个大功能,精简指令集需要指令较多,而复杂指令集需要指令少,加起来到底谁耗电 多呢.还有,现在处理器普遍采用微指令,大的指令会被拆分成更小的指令,以达到更高的流水线效率.简单指令集的单条微指令和复杂指令集的单条微指令相比的 话,情况就更复杂.我手头没有关于比较的具体数据,但是至少前文所列出关于功耗和指令集相关的解释不是很有说服力.。

首先,我们将数组的查找过程绘制成一棵二叉树,如果查找的关键字不是中间记录的话,折半查找等于是把静态有序

否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。因此, 在磁盘上进行查找的次数、即待查找关键字所在结点在b- 树上的层次树, 是决定b树查找效率的首要因素。首先,无索引的表,查询时,是按照顺序存续的方法扫描每个记录来查找符合条件的记录,这样效率十分低下,举个例子,如果我们将字典的汉字随即打乱,没有前面的按照拼音或者部首查询,那么我们想找一个字,按照顺序的方式去一页页的找,这样效率有多底,大家可以想象。

堆排序是一种树形选择排序,在排序过程中,将a[n]看成是完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系来选择最小的元素。ps: 树的路径长度是从树根到树中每一结点的路径长度之和.在结点数目相同的二叉树中,完全二叉树的路径长度最短.。9.完全二叉树的顺序存储方案,是指将完全二叉树的结点从上至下、从左至右一次存放到一个顺序结构的数组中。

叉树,但同样相同的推导可以得出,最坏情况是查找到关键字或查找失败的次数为[log2n]+1,最好的情况是1次。

因此最终我们折半算法的时间复杂度为O(logn),它显然远远好于顺序查找的O(n)时间复杂度了。

8 查找结构:符号表,二叉查找树,二叉查找树的查找、插入和删除操作,avl树,高度平衡,ll, lr, rr, rl 旋转, 插入算法,时间复杂性分析,b树,m叉查找树,m叉查找树的查找,b树的定义和性质,b树的插入操作,b树的删除操作,静态散列,散列表,散列函数,溢出处理,开放寻址,链接。 3.熟练掌握单链表的插入、删除和查询算法...元素删除、元素查找、测表空、求表长等单 链表的基本操作算法有了进一步的了解...。(2) 线性表adt顺序存储实现中的创建、查找、插入和删除等基本操作及相关算法,线性表adt链式存储实现中单链表、循环链表和双向链表的创建、查找、插入和删除等基本操作及相关算法。


本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-106859-1.html

相关阅读
    发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

    热点图片
    拼命载入中...