三种不同查找算法实际查找性能的对比

   一、查找问题的介绍

查找问题就是在给定的集合(或者是多重集,它允许多个元素具有相同的值)中找寻一个给定的值,我们称之为查找键。有许多查找算法可供选择,其中既包括直截了当的顺序搜索,也包括效率极高但应用受限的折半查找,还有那些将原集合用另一种形式表示以方便查找的算法。最后一类算法对于现实应用具有特别重要的价值,因为它们对于大型数据库的信息存取来说是不可或缺的。

对于查找来说,没有一种算法在任何情况下都是最优的。有些算法速度比其他算法快,但需要较多的存储空间;有些算法速度非常快,但仅适用于有序的数组,诸如此类。和排序算法不同,查找算法没有稳定性问题,但会发生其他问题。具体来说,如果应用里的数据相对于查找次数频繁变化,查找问题就必须结合另外两种操作一起考虑:在数据集合中添加和删除元素的操作。在这种情况下,必须自习选择数据结构和算法,以便在各种操作的需求之间达到一个平衡。而且,对于用于高效查找的特大型数据集合来说,如何组织其结构是一项不同寻常的挑战,而这对实际应用具有非常重要的意义。

针对查找问题采用了三种方法:线性表直接查找,二叉排序树查找,平衡二叉排序树查找三种方法。

1)其中线性表(Linear List,LL)直接查找,通过将数据集合存储在数组中,每次从数组首地址开始一直搜索到数组末尾,直到查找到待查元素和到达数组末尾为止。并针对该方法给出了一个优化的算法,对数组中的元素增加一个频度域,将查找频度最高的元素放在数组最前面,依次按频度对数组中元素进行排序。

2)二叉排序树(Binary Sort Tree,BST)查找,BST又称二叉搜索树,其定义为:二叉排序树或者是一颗空树,或者是具有如下性质的二叉树:①若左子树不空,则左子树上所有节点的值均小于它的根节点的值;②若右子树不空,则右子树上所有节点的值均大于它的根节点的值;③左、右子树也分别是二叉排序树;④没有键值相等的节点。从BST的定义中可知,在BST中查找一个元素的过程,即从根节点开始,每次根据待查元素与根节点的比较,决定查找成功或者依左或右子树查找,直到找到待查元素或者都到叶子节点为止。

3)平衡二叉查找树(Adelson-Velskii and Landis,AVL树),一棵AVL树是一棵二叉查找树,其中每个节点的平衡因子定义为该节点左子树和右子树的高度差,这个平衡因子要么是0,要么为+1或者-1(一棵空树的高度定义为-1)。因此AVL树是一种特殊的二叉查找树,其左右分支深度比较平衡,这样就缩短了树的高度,从而降低了查找的次数。在AVL树种查找元素的过程类似在二叉排序树中查找元素。

二、对查找问题的理论分析

设集合中的数据个数为n,则在采用线性表直接存储时,每次查找一个元素,在最好的情况下,时间复杂度是o(1),最坏的情况下时间复杂度是o(n),因此平均查找长度是

在对线性表直接查找进行优化的算法中,增加了频度域,数组中数据按照数据查找的频度从高到低排列,在这种算法上,最好的情况下,时间复杂度是o(1),最坏的情况下时间复杂度是o(n)。数据的平均查找长度依赖于所查找的序列。但可以确定的是,其查找长度低于优化前的查找长度

在分析二叉排序树的理论查找性能时,我们首先要清楚二叉排序树的形态,因为当二叉排序树的形态不同,其树的深度就会不同,因而查找的性能也会不同。在极端的情况,二叉排序树退化为一个单分支的树,则其查找性能跟线性表直接查找相同。在这里我们可以分析,对一棵随机生成的二叉排序树,其平均查找性能优于线性表直接查找。为了确定二叉排序树查找性能的上界和下界,我们首先分析一棵完全平衡的二叉排序树,即既是一棵平衡二叉树,又是一棵完全二叉树。假设每一个节点的查找频率相同,则完全平衡二叉查找树的平均查找长度为

因此随机生成的一棵二叉查找树的平均长度为

上述三种方法从时间复杂度上来说,查找一个数据的时间复杂度都是o(n),空间复杂度均需要o(n)大小的辅助存储空间。

三、实验仿真结果

实验在VC6.0平台上,采用的C语言编写程序,将实验中测试的数据存储在record.txt文本中,再将文本数据导入到matlab中进行可视化比较。

图3.1和图3.2是测试不同查找算法的运行所耗费的时间的实时输出截图。其中图3.1是样本数量较少情况下的运行输出图,图3.2是样本数量较大时候的运行输出图。每一次输出会连续输出四组数据,每一组数据包含两个数值,第一个数值表示的是查找所耗费总的时间,第二个数值是查找中总的查找长度。

并将运行中的数据记录在文件中,图3.3和图3.4均是在测试样本数量不同时的各算法查找性能的评价值。每一行为一个样本的记录,包含九个数字,第一个数值是测试样本的数量,后面的八个数字,两个一组,共四组,第一个数字是查找所耗费的时间,第二个数字是查找总的长度,四组数字分别对应,直接连表查找,带频度的连表查找,二叉查找树和AVL树查找。在图3.4中,有的部分数字是负数,那是因为查找的长度值超过了C语言中int类型的最大数值表示范围,产生了溢出。

在图3.5中,是四种算法的查找耗费时间的对比图,通过将上面记录的实验数据导入到Matlab中,生成的对比图。从图中我们可以直观看到四种算法中,线性表直接查找所耗费的时间最长,带频度的线性变性能次之,相对比,二叉查找树和AVL树的查找性能要好得多,耗费的时间也大大的低于线性表。随着样本数量的增加,线性表查找的时间耗费整体趋势呈正比例增长,而二叉排序树和二叉查找树的时间变化比较缓慢。

图3.6和图3.7分别是对图3.5的局部进行放大所成的图。从这两幅图中,可以直观的看到两种线性表和两种二叉树数据结构算法的性能对比。

在下面,我们将呈现各算法总的查找长度的性能对比图。在图3.8中,我们可以看到,相对于直接线性表和带频度的线性表来说,二叉查找树和AVl树的总的查找长度要低得多。而图中在接近900000样本时,所出现的查找长度变为负数,是因为存储查找长度的int类型变量发生了正向溢出。

图3.9分别为对图3.8的局部放大,更清晰的呈现其性能的对比。从图3.8中可以直观的看到,带频度的线性表能够在线性表直接查找的基础上改进查找性能,降低总的查找长度。从图3.9中可以看到,AVL树的查找性能在平均的情况向,其查找所耗费的总的查找长度,大约为二叉查找树的3/4。

时间: 2024-10-07 23:04:48

三种不同查找算法实际查找性能的对比的相关文章

算法复杂度,及三种主要排序算法的研究

一.时间复杂度 1.时间频度  T(n),n为问题的规模 即--算法中语句的执行次数.又叫语句频度. 2.时间复杂度 记作 O( f(n) ),这里的f(n)是一个T(n)的同数量级函数. 如O(1)表示算法的语句执行次数为一个常数,不随规模n的增长而增长: 又如T(n)=n^2+3n+4与T(n)=4n^2+2n+1它们的频度不同, 但时间复杂度相同,都为O(n^2). 3.算法的性能 主要用算法的 时间复杂度 的数量级来评价一个算法的时间性能. 二.空间复杂度 S(n),包括3方面: 1.算

Java中常用的查找算法——顺序查找和二分查找

Java中常用的查找算法——顺序查找和二分查找 一.顺序查找: a) 原理:顺序查找就是按顺序从头到尾依次往下查找,找到数据,则提前结束查找,找不到便一直查找下去,直到数据最后一位. b) 图例说明: 原始数据:int[] a={4,6,2,8,1,9,0,3}; 要查找数字:8 代码演示: import java.util.Scanner; /* * 顺序查找 */ public class SequelSearch { public static void main(String[] arg

算法:三种简单排序算法

排序算法比较常见的有:冒泡排序.简单选择排序.直接插入排序:希尔排序.堆排序.归并排序和快速排序算法等.今天先学习一下前面三种比较简单的算法.排序的相关概念: ①排序的稳定性:两个或多个元素相等,排序过后仍然是原来的顺序则为稳定排序. ②内部排序:排序过程都在内存中进行:外部排序:需要对外存进行访问的排序过程. ③内排序算法性能因素:1.时间性能,比较与移动:2.辅助空间:3.算法复杂性 实例:冒泡排序.简单选择排序与直接插入排序 #include "stdio.h" #define

查找算法-二分查找

查找算法-二分查找 标题 二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法.但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列. 过程 首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功:否则利用中间位置记录将表分成前.后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表.重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找

K-means聚类算法的三种改进(K-means++,ISODATA,Kernel K-means)介绍与对比

  一.概述 在本篇文章中将对四种聚类算法(K-means,K-means++,ISODATA和Kernel K-means)进行详细介绍,并利用数据集来真实地反映这四种算法之间的区别. 首先需要明确的是上述四种算法都属于"硬聚类"算法,即数据集中每一个样本都是被100%确定得分到某一个类别中.与之相对的"软聚类"可以理解为每个样本是以一定的概率被分到某一个类别中. 先简要阐述下上述四种算法之间的关系,已经了解过经典K-means算法的读者应该会有所体会.没有了解过

mongodb三种存储引擎高并发更新性能专题测试

背景说明 近期北京理财频道反馈用来存放股市实时数据的MongoDB数据库写响应请求很慢,难以跟上业务写入速度水平.我们分析了线上现场的情况,发现去年升级到SSD磁盘后,数据持久化的磁盘IO开销已经不是瓶颈.通过日志分析,线上单次写入(更新)请求大多在数十毫秒这个级别,数据库端观察几个主要的db在繁忙时通常有95%以上的时间在进行锁等待.线上数据库并发很高,接近1000个连接,所以怀疑是并发争用表锁导致性能不足. 我们知道MongoDB的mmap存储引擎一直是库/表级锁,因此任何写操作并发越高锁争

js三种基础数组排序算法整理

数组排序,大概是每个程序员必须掌握的基本算法 ,作为一个刚入门的前端小卒,再被各种面试各种排序折磨过后 ,看过很多别人写的 算法 ,但看总归是理解的不是那么深刻 ,便想着自己整理一下这最基本的三个排序算法 ,希望对还在学习的你有些许帮助 .比较基本的三种算法 .冒泡.插入 .快速 . 首先来看冒泡排序法 ,基本原理其实就是对数组进行两层循环,外层循环控制次数,数组中有多少个成员,便是要进行多少次内层遍历,不断地将当前成员和下一成员进行对比 ,其实在群众偶其中有很多次是重复对比的 ,先看这样一个写

三种方式实例化一个类的性能情况

源内容:http://www.cnblogs.com/shouce/p/5558095.html#undefined 下面的内容是根据“源内容”进行了整改.补充. 三种方式实例化一类,包括无参数构造形式与有参数构造形式性能测试. 使用new关键字创建类实例(常用方式). 使用Activator激活器类创建类实例(Activator用以在本地或从远程创建对象类型,或获取对现有远程对象的引用). 使用Assembly程序集创建类实例(Assembly表示一个程序集,它是一个可重用.无版本冲突并且可自

Jvm(25),回收策略----前三种基本回收算法对比

这里LZ给各位总结一下三个算法的共同点以及它们各自的优势劣势,让各位对比一下,想必会更加清晰. 它们的共同点主要有以下两点. 三个算法都基于根搜索算法去判断一个对象是否应该被回收,而支撑根搜索算法可以正常工作的理论依据,就是语法中变量作用域的相关内容.因此,要想防止内存泄露,最 根本的办法就是掌握好变量作用域,而不应该使用前面内存管理杂谈一章中所提到的 C/C++式内存管理方式. 在GC线程开启时,或者说GC过程开始时,它们都要暂停应用程序(stop the world). 它们的区别LZ按照下