(十二)数据结构之静态查找

数据结构静态查找:顺序查找、折半查找、斐波那契查找、索引顺序表查找

1.内容概括

大致内容: 介绍几种静态查找方法的算法分析,代码实现过程以及一些需要注意易错区。

2.顺序查找算法分析

算法分析: 顺序查找十分简单,顾名思义顺着顺序表的顺序进行查找。
平均查找步数:

设总共n个数。
当查找一定成功时,查找到每一个数的概率都是:1/n。
可以得到当查找成功时,平均查找步数为:1/n * (1+2+3+…+n) = (n+1)/2
但实际上查找时不全会成功,因此我们需要加上查找失败时的查找步数来计算真正的平均步数。
失败+成功平均查找步数为:(n+1)/2 + 1/(2n) * (1+2+3+…+n) = 3/4 * (n-1)

2.1优缺点

 优点:算法简单,适应性强。无论是数组还是链表等都可以用此方法
 缺点:查找广度大,当数据量大是效率十分低下

2.2代码实现

//==================================================================================
int FlowOrderSearch(int *p) //顺序查找
{
	int TargetNum = UserInput();  //用户输入查找内容

	StartTime = clock();
	for (int i = 0; i < NUM; ++i) if (*(p + i) == TargetNum) {EndTime = clock(); cout << (StartTime - EndTime) / CLOCKS_PER_SEC << "s" << endl;return i + 1;}
	EndTime = clock();
	return -1; //查找失败
}
//==================================================================================

2.3一点改进

很多时候我们对数据元素的查找并不都是相同概率的,我们可能对某些元素的查找频率高于其他元素。这时候就需要我们调整顺序表元素的相对位置。假设每次从1号开始查找,第一种做法是,查找的同时将这些数据按照频度排序,第二种做法是将最近一次查询的数据移动到顺序表的最前方,这样经过多次查找之后,顺序表前部分就是查找频度更高的元素集合,这时查找的效率会有很大提升,特别是数据元素非常多时

3.折半查找算法分析

算法分析: 附设三个伪指针low指向第一个元素, high指向最后一个元素,mid始终指向数组的第(low+high)/2个元素。如果mid所指元素大于需要查找的元素target,则high = mid - 1,若小于则low=mid+1,若等于则直接返回mid的值。一直循环直到low>high为止。
平均查找步数:

设总共有n个数据。
计算方法:
由这n个数据建立判定树,(即二叉搜索树),那么查找成功时的最长长度为树的深度。
又,

有n个节点的判定树的最大深度为log2 n(2是对数底数)+1
(注:log2 n的计算结果向下取整,可以举几个例子验证。并且查找失败时的查找长度也不会超过这个结果)

最终平均的查找长度是:log2 ^(n+1) - 1(引用书上的计算结果)
可见折半查找的平均效率比顺序查找更高

3.1 优缺点

 优点:1.效率较顺序查找更高
 缺点:1.只适用于顺序存储的数据 2.只适用于有序的数据

3.2代码实现

int HalfSearch(int *p) //折半查找
{
	int front = 0, back = NUM - 1, mid;

	int TargetNum = UserInput(); //用户输入查找内容
	StartTime = clock();
	while(front <= back) { //循环开始
		mid = (front + back) / 2;
		if (p[mid] > TargetNum)      back = mid - 1;
		else if (p[mid] < TargetNum) front = mid + 1;
		else 					  {EndTime = clock(); return mid + 1;}
	}
	EndTime = clock();
	return -1; //查找失败
}

4.*斐波那契查找算法分析

斐波那契查找算法分析: (这个查找方法用的人比较少,以至于我在复习数据结构全书仔细看书时才注意到还有这种查找方法的存在。)
首先了解一些斐波那契数列,

可定义为:
F0 = 0, F1 = 1, Fi = Fi-1 + Fi-2(i>=2)的序列组成被称为斐波那契数列

那么这种查找方法可以是:以斐波那契数列的特点将其进行分割,
例如一共有10个数据那么可以把这十个数据分为4+6或者3+7两部分(都可以),即:4,6,10(刚好是斐波那契数列的特点),那么我们抽取中间的那个,第6个元素和目标元素进行比较,若小于目标数则在7-10这4个数之间重复进行此做法,若大于则在1-5这6个数之间继续重复此做法。

效率分析:
斐波那契查找的平均性能比折半查找要好,但是最坏情况下却比折半查找要差一些。(虽然仍是O(log n))

4.1优缺点

优点:1.平均性能比折半查找更好 2.对数据进行分割时只需要进行加减法即可
缺点:1.emm,,书上没有提到,但是这里我们可以将这种查找看成折半查找的进化版(实际上非常相似)

4.2代码实现

int FabonaciSearch(int *p, int length) { //斐波那契查找
	int TargetNum = UserInput();
	int low = 0, high = length - 1, pos;
	do {
		pos = high + low + 1; pos = 1 + (pos /= 2); //这里我把长度为2n的数据分成n-1和n+1两部分,2n+1分成n和n+1
		if (p[pos - 1] > TargetNum)      high = pos - 2;
		else if (p[pos - 1] < TargetNum) low = pos;
		else                             return pos;
	} while(low <= high);
	return -1; //查找失败
}

5.索引顺序表查找算法分析

索引顺序表查找算法分析: 使用索引顺序表查找的一个大前提是:数据元素或者有序或者分块有序。有序就不提了,而分块有序的意思是,后一块中的最小元素一定会大于或者等于前一块中的最大数据元素。(有没有很类似于三阶B树的感觉?后面我们会写到的)
平均查找长度:

一般情况下,进行分块查找可将长度为n的表均匀分为b块,设每块有s个元素,那么b = n/s(若为小数则向上取整。
那么我们通过计算得到平均查找长度为: 1/2 * (n/s + s) + 1
并且通过上述式子进行求导我们可以知道当s取根号n时能得到最小平均查找长度
这个效率大于顺序查找,但是还远不及折半查找

5.1优缺点

这个查找方法属于性能介于折半查找与顺序查找之间的一种查找方法,优缺点方面并没有什么可分析的,只需要注意它的使用情况:或者有序或者分块有序,即可。

5.2代码实现

//索引顺序表的查找
int HeadTableSearch(int *b, int (*b2)[2], int num) { //该表分块有序,下一块中的每一个关键字均大于前一块中的最大关键字
	int TargetNum = UserInput(), pos;
	StartTime = clock();
	for (pos = 0; pos < num; ++pos) if (TargetNum < **(b2 + pos)) break; if (pos == num) return -1; //查找失败
	//在*(*(b2 + pos - 1) + 1) 和 *(*(b2 + pos) + 1) 之间进行顺序查找,包括本身!
	int BegPos = pos == 0 ? 0 : *(*(b2 + pos) + 1), EndPos = pos == num - 1 ? 9 : *(*(b2 + pos + 1) + 1);
	for (int i = BegPos; i <= EndPos; ++i) if (b[i] == TargetNum) {EndTime = clock(); return i + 1;}
	EndTime = clock();
	return -1; //查找失败
}
int main() {
	int b[10] = {12, 34, 11, 55, 36, 44, 56, 66, 78, 72};
	int b2[3][2] = {{34, 0}, {55, 3}, {78, 6}};
	JudgeAndDisplayResult(HeadTableSearch(b, b2, 3));
	return 0;
}

5.3一点改进

在对相应块进行查找时,可以改进顺序查找为折半查找,这样性能会有进一步的提升,这里不做赘述。

6.End

这一篇博客主讲静态查找:只查询有无,不能对表进行操作。
而下一篇博客会是几种动态查找算法的内容介绍,当查询到此元素时返回它的位置(或者指针),当无此元素时可以插入到表中并返回其位置或指针,也是非常常用的查找方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值