【查找算法】——顺序查找、折半查找、分块查找(索引查找)

转载出处:http://www.cnblogs.com/kunhu/p/3634562.html


查找算法


概述:

查找算法:就是在是数据元素集合中查看是否存在于指定的关键字相等的元素。

查找分为两种:静态查找动态查找

1) 静态查找:是指在数据元素集合中查找与给定的关键字相等的元素。

2) 动态查找:就是指在查找过程中,如果数据元素集合中不存在与给定的关键字相等的元素,则将该元素插入到数据元素集合中。


静态查找主要包括顺序表、有序顺序表和索引顺序表的查找。

1) 顺序表的查找,就是指从表的第一个元素与给定关键字比较,直到表的最后。

2) 有序顺序表的查找,在查找的过程中如果给定的关键字大于表的元素,就可以停止查找,说明表中不存在该元素(假设表中的元素按照关键字从小到大排列,并且查找从第一个元素开始比较)

3) 索引顺序表的查找是为主表建立一个索引,根据索引确定元素所在的范围,这样可以有效地提高查找的效率。

 

动态查找主要包括二叉排序树平衡二叉树B-树B+树

这些都是利用二叉树和树的特点对数据元素集合进行排序,通过将元素插入到二叉树或树中建立二叉树或树,然后通过对二叉树或树的遍历按照从小到大输出元素的序列。

 

散列表是利用散列函数的映射关系直接确定要查找元素的位置,大大减少了与元素的关键字的比较次数。

建立散列表的方法主要有直接定址法平方取中法折叠法除留余数法(最常用)等。

但是会存在冲突,解决冲突的最为常用的方法主要有两个:开放定址法链地址法

 

一.静态查找

1.顺序表的查找——顺序查找

顺序查找(Sequential Search)又称为线性查找,是一种最简单的查找方法。
 

        从表的一端开始,向另一端逐个按要查找的值key 与关键码key进行比较,若找到,查找成功,并给出数据元素在表中的位置;若整个表检测完,仍未找到与关键码相同的key值,则查找失败,给出失败信息。

说白了就是,从头到尾,一个一个地比,找着相同的就成功,找不到就失败。很明显的缺点就是查找效率低。


【适用性】:适用于线性表的顺序存储结构和链式存储结构。

 平均查找长度=(n+1)/2.

【顺序查找优缺点】:

缺点:是当n 很大时,平均查找长度较大,效率低;

优点:是对表中数据元素的存储没有要求。另外,对于线性链表,只能进行顺序查找。

#include<iostream>
using namespace std;

#define MAX 11

typedef int key_type;

typedef struct element
{
	key_type key;   //关键字 
}elem;

int seq_search(elem e[], key_type key, int n)
{
	int i = 0;
	while(i < n && e[i].key != key)
	{
		i++;
	}
	
	if(i < n)
		return i;
	else 
		return -1;
}
 
 int main(int argc, char** argv)
 {
 	elem linelist[MAX] = {1,5,9,7,12,11,10,8,6,2,3};
 	int n = 11;
 	int i = 0;
 	key_type key = 8;
 	printf("线性表中的元素为: \n");
 	
 	while(i < n)
 	{
		printf("%d\n",linelist[i].key);
		i++; 
	}	
	
	printf("\n关键字[%d]在线性表中的位置下标为[%d]\n", key, seq_search(linelist, key, n));
	
	getchar();
	system("pause");
 }


2.有序顺序表的查找——折半查找

        在有序表中,取中间元素作为比较对象,若给定值与中间元素的关键码key相等,则查找成功;若给定值小于中间元素的关键码,则在中间元素的左半区继续查找;若给定值大于中间元素的关键码,则在中间元素的右半区继续查找。不断重复上述查找过程,直到查找成功,或所查找的区域无数据元素,查找失败。

【步骤】
① low=0;high=length-1;                                                          // 设置初始区间
② 当low>high 时,返回查找失败信息                                         // 表空,查找失败
③ 当low<=high,mid=(low+high)/2;                                           //确定该区间的中点位置
      a. 若key < elem[mid].key,high = mid-1;转②                    // 查找在左半区进行
      b. 若key > elem[mid].key,low  = mid+1; 转②                  // 查找在右半区进行
      c. 若key = elem[mid].key,返回数据元素在表中位置        // 查找成功

 

有序表按关键码排列如下:

3,  5,  6,  8,  9,  12,  17,  23,  30,  35,  39,  42

在表中查找关键码为9的数据元素:

#include<iostream>
using namespace std;

#define MAX 12

typedef int key_type;

typedef struct element
{
	key_type key;   //关键字 
}elem;


int binary_search(elem e[], key_type key, int n)
{
	int low = 0, high = n - 1;
	int mid;
	
	while(low <= high)
	{
		mid = (low + high)/2;
		
		if(e[mid].key == key)
			return mid;
		else if(key < e[mid].key)
			high = mid - 1;
		     else
			low = mid + 1;
	}
	
	return -1; //没找到 	
}

 
 int main(int argc, char** argv)
 {
 	elem linelist[MAX] = {3,5,6,8,9,12,17,23,30,35,39,42};
 	int n = 12;
 	int i = 0;
 	key_type key = 9;
 	printf("线性表中的元素为: \n");
 	
 	while(i < n)
 	{
		printf("%d\n",linelist[i].key);
		i++; 
	}	
	
	printf("\n关键字[%d]在线性表中的位置下标为[%d]\n", key, binary_search(linelist, key, n));
	
	getchar();
	system("pause");
 }

折半查找算法的平均查找长度为O(logn),与顺序查找方法相比,折半查找算法的效率高。速度比顺序查找快。
但折半查找只能使用于有序表,需要对n个元素预先进行排序(仅限于顺序存储结构,对于线性链表无法进行折半查找)。
 

3.分块查找(索引查找)

分块查找又称索引顺序查找,是对顺序查找的一种改进。分块查找要求将查找表分成 若干个子表,并对子表建立索引表,查找表的每一个子表由索引表中的索引项确定。索引项包括两个字段:关键码字段(存放对应子表中的最大关键码值) ;指针字段(存放指向对 应子表的指针) ,并且要求索引项按关键码字段有序。查找时,先用给定值key 在索引表中 检测索引项,以确定所要进行的查找在查找表中的查找分块(由于索引项按关键码字段有序,可用顺序查找或折半查找) ,然后,再对该分块进行顺序查找。


如关键码集合为:

                           (8, 20, 13, 17, 40, 42, 45, 32, 49, 58, 50, 52, 67, 79, 78, 80)

按关键码值20,45,58, 80分为四块建立索引表。

                              

分块查找的函数分为如下两步:
a)首先确定待查找的结点属于哪一块,即查找所在的块;
b)然后,在块内查找要查的结点。

设表共n个结点,分b块,s=n/b

(分块查找索引表)平均查找长度=Log2n/s+1+s/2

(顺序查找索引表)平均查找长度=(S2+2S+n)/(2S)

#include<iostream>
using namespace std;

#define MAX 16

typedef int key_type;

struct elem
{
	key_type key; //关键字 
};

//索引结构 
struct index         
{
	key_type key; //索引值 
	long low;     //起始位置 
	long high;    //终止位置 
};

int index_search(elem e[], key_type key, int n, index idx[], int idx_length)
{
	int low = 0;
	int high = idx_length - 1;
	int mid;
	
	//采用折半查找在索引表里找到关键字所在的块
	while(low <= high)
	{
		mid = (low + high)/2;
		if(key < idx[mid].key)
			high = mid - 1;
		else if(key > idx[mid].key)
			low = mid + 1;
		     else
			break;
	} 
	
	//采用顺序查找的方法从块中查找关键值
	int i = idx[mid].low;
	
	while(i <= idx[mid].high && e[i].key != key)
	{
		i++;
	} 
	
	if(i > idx[mid].high)
		return -1;
	else
		return i;
}


int main(int argc, char** argv)
{
	elem linelist[MAX] = {
		8, 20, 13, 17,
		40, 42, 45, 32,
		49, 58, 50, 52,
		67, 79, 78, 80
	};
	
	int n = sizeof(linelist) / sizeof(elem);
	key_type key = 50;
	
	//建立索引表
	index index_table[4] = {{20,0,3}, {45,4,7}, {58,8,11}, {80,12,15}}; 
	int idx_length = sizeof(index_table) / sizeof(index);
	
	printf("线性表中的元素为:\n");

	int i = 0;
	
	while(i < n) 
	{
		printf("%d\n",linelist[i].key);
		i++;
	}
	
	printf("\n关键字[%d]在线性表中的位置下标为[%d]", key, index_search(linelist, key, n, index_table, idx_length));
	
	getchar();
	system("pause");
}


  • 5
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值