一、查找的定义
无论是静态查找还是动态查找,都要有查找的对象,也就是包含很多同类型数据的“表”,这个“表”可以理解为一个由同类型数据元素组成的一个“集合”,该集合可以用各种容器来存储,例如数组、链表、树等,我们统称这些存储数据的数据结构为——查找表。可见,查找表有时是我们传统意义的表,有时候是很复杂的一种结构。
二、静态查找和动态查找
1、静态查找
静态查找就是我们平时概念中的查找,是“真正的查找”。之所以说静态查找是真正的查找,因为在静态查找过程中仅仅是执行“查找”的操作,即:(1)查看某特定的关键字是否在表中(判断性查找);(2)检索某特定关键字数据元素的各种属性(检索性查找)。这两种操作都只是获取已经存在的一个表中的数据信息,不对表的数据元素和结构进行任何改变,这就是所谓的静态查找。
2、动态查找
看到上面静态查找的概念,动态查找就很好理解了,个人总觉得动态查找不像是“查找”,更像是一个对表进行“创建、扩充、修改、删除”的过程。动态查找的过程中对表的操作会多两个动作:(1)首先也有一个“判断性查找”的过程,如果某特定的关键字在表中不存在,则按照一定的规则将其插入表中;(2)如果已经存在,则可以对其执行删除操作。动态查找的过程虽然只是多了“插入”和“删除”的操作,但是在对具体的表执行这两种操作时,往往并不是那么简单。
哪种查找对应各自查找表,如有序表可以为静态查找表,也可以为动态查找表。依查找方式决定。
三、几种静态查找
1、顺序查找
顺序查找是一种最基本、直接的查找方法。它从线性表的一端开始,向另一端逐个取出数据元素的关键字,并与要找的关键字K进行比较,以判定是否存在要找的数据元素。
以数组存储为例,设数据元素从下标为1的数组单元到下标为Last的单元存放。为了简化算法,使得从后向前查找失败时,不必判断表是否检查完毕,可以在查找开始前,作为哨兵将要查找的关键字K存入下标为0的数组单元。这样,即使原表1~Last单元中没有关键字为K的记录,算法再多一次查找下标为0的单元,也会找到元素而终止,而此时返回数组下标值0表明查找失败。
代码:
Position SequentialSearch(List Tbl, ElementType K)
{
// 在顺序存储的表Tbl中查找关键字为K的数据元素,使用“哨兵”
Position i;
Tbl->Data[0] = K; // 建立哨兵
for(i = Tbl->Last ; Tbl->Data[i] != K ; i --);
return i; // 查找成功返回数据元素所在单元下标;查找不成功返回0
}
2、二分查找
顺序查找算法的时间复杂度是线性的。而当线性表中数据元素是按大小排列存放时,可以设计一种更高效率的新算法---二分查找。二分查找也称为折半查找,是针对线性表中数据的存放是有序的这一特性,而采用的一种有效方法。
代码:
const int N = 1e5 + 10;
typedef int ElementType;
typedef int Position;
#define NotFound -1
typedef struct LNode *PtrToLNode;
struct LNode // 节点表示的东西
{
int Data[N]; // 数据
Position Last; // 位置
};
typedef PtrToLNode List;
// 二分查找的非递归实现
Position BinarySearch(List L, ElementType X)
{
// 在顺序表L中查找关键字为X的数据元素
Position Left, Right, Mid;
Left = 1;
Right = L->Last;
while(Left <= Right)
{
Mid = (Left + Right) / 2;
if(L->Data[Mid] > X) Right = Mid - 1;
else if(L->Data[Mid] < X) Left = Mid + 1;
else return Mid;
}
return NotFound;
}
与顺序查找算法不同,我们不必通过在0单元增加哨兵来判断查找是否成功,而是通过判断是否还有合理的剩余查找范围。因此,其实可以将表中元素从0单元开始存起,那么查找失败时算法返回的NotFound就应该是一个负数(-1)。
算法时间复杂度分析:当线性表中没有所要查找的元素时,算法复杂度达到最大。设经过k步,查找范围从n减小到1。因为每步查找范围时上一步的二分之一,可得到关系n / 2^k = 1,即k=
logn。由此可以得到结论:二分查找算法具有对数的时间复杂度O(log n)。
至此,我们已知道顺序查找和二分查找都属于静态查找方法,所谓静态是指数据一旦建立起来就基本不添加新的数据元素,也不删除原有的数据元素。因此用数组存放数据并通过下标访问数据元素既方便又高效。但当数据集变化频繁,采用链式存储时,这种基于有序性的二分查找策略就不适用了,但基于二分查找思路的动态结构方法二叉查找树是可以的。
本文介绍了查找表的概念,包括静态查找和动态查找的定义。静态查找主要涉及查找和检索操作,而动态查找则包括插入和删除操作。顺序查找是最基本的查找方法,适用于未排序的线性表,而二分查找则利用了数据的有序性,提高了查找效率。文章还提供了两种查找算法的代码实现,并对比了它们的时间复杂度。
861

被折叠的 条评论
为什么被折叠?



