关于几种查找方法的总结

一、基于线性结构的查找方法

1.顺序查找

1.1.1查找表结构特点

无序线性表

1.2.1查找基本思想

从线性表的一端开始,逐个进行元素关键字和给定值的比较,若某个元素关键字和给定值相等,则查找成功;反之,若直至线性表的表尾,都未有元素关键字和给定值相等,则查找不成功。

1.3.1步骤

  1. 将当前位置设为表头;
  2. 获取当前位置的值,若该值与带查找的值相等,返回查找成功,否则进行步骤3;
  3. 将当前位置设置为下一位置,返回步骤二步骤2;
  4. 查找至表尾,没有查找成功,则查找失败。

1.4.1核心伪代码

bool find(List<int>L,int k)
{
	 int it;
     for(L.setStart();L.getValue(it);L.next())
     {if(k==it)  retuen true;}
     return false;
}

1.5.1性能(特点)

算法本身无额外的空间开销;最差情况下需要Θ(n)的时间

1.6.1备注

1.该方法简单,比较直须判定相等或者不相等,易于实现,适用范围广。
2.该方法不适合表长较大的查找。

1.1.2查找表结构特点

自组织线性表,有三种自组织启发规则:计数方法、移植前端法、转置法。

1.2.2查找基本思想

根据实际的记录访问模式在线性表中修改记录顺序,使用自组织启发规则决定如何重新排列线性表,查找时,依然执行无序线性表的顺序查找。

1.3.2步骤

步骤与在无序线性表中查找的步骤大致相同,不同的是当查找成功时,启用自组织启发规则。

1.4.2核心伪代码

bool find(int s,void(*visit)(Node *A))
{//visit为实现自组织启发规则的函数。
	curr = head;
	for (int i = 1; i <=getSize(); i ++)
	{
		curr=curr->getNext();
		if (curr->element.a[0] == s.a[0]&& curr->element.a[1] == s.a[1]) 
 		{visit(curr);  return true;}
	} 
	return false;
}

1.5.2性能(特点)

该算法不需要额外的空间开销;

1.6.2备注

1.实现自组织线性表最好的方式是链表;
2.无需对线性表依关键码大小进行排序,插入一条新纪录(访问概率小)的代价很低;
3.自组织线性表实现很简单,对于小规模的记录可能更有效率。

2.二分查找

2.1查找表结构特点

  1. 线性表是有序的
  2. 线性表采用顺序储存结构

2.2查找基本思想

对待查找的有序线性表不断的折半,逐步缩小范围直到找到或者找不到元素为止

2.3步骤

  1. 定义两个指针low和high分别指向待查元素的下界和上界,指针mid指示待查区间的中间位置;
  2. 若待查元素的范围大于1,则取中间位置元素与给定元素比较,若相等,则查找成功,结束;若小于,则将上界设为mid-1;若大于,则将下届设为mid+1;
  3. 继续循环查找,否则查找失败

2.4核心伪代码

int binary(int a[], int n, int value)
{
	int low=0,high=n-1;
	while(low<=high)
	{
		int mid=low+(high-low)/2;
		//防止两者之和溢出
		if(a[mid]==value) return mid;
		else if(a[mid]>value) 
				high=mid-1;
		else if(a[mid]<value)
				low=mid+1;
	}
	return n;//查找不成功   
}

2.5性能(特点)

时间开销:最差和平均时间复杂度为Θ(logn);空间开销:只需要储存被查找的元素,算法本身的空间开销是O(1).

2.6备注

该代码适用于有序数组中不存在重复元素情况;该方法适用于不经常变动而查找频繁的有序列表;而且储存的数据量不宜过大,因为连续内存空间可能不足。

3.分块查找

3.1查找表结构特点

无序线性表,线性表可以用数组或者链表储存;把线性表分成若干块,块与块之间进行排序,构建有序检索表,检索表可用数组储存,此时可用二分法查找。

3.2查找基本思想

  1. 首先查找检索表,可以采用二分查找或顺序查找;
  2. 然后在已经确定的块中进行顺序查找。

3.3步骤

索引表以顺序查找为例:

1.从索引表的表头开始遍历,如果存在大于等于关键字k的值,就进行第二步,如果不存在则搜索失败;
2.根据该块的起始位置指针找到的线性表的对应位置,然后遍历该块线性表,若存在相等的值则查找成功,否则查找失败。

3.4核心伪代码

typedef struct indexType
{
 	ketType maxkey;
	//块中最大的关键字
	int startpos;//块的起始位置指针
	bool Block_search(RecType ST[],index ind[],ketTypw k,int n, in b)
	{//在索引表中搜索关键字为k的记录,n为表长,b为块数
			int i=0,j,k;
			while(i<b&&ind[i].maxkey<k)i++;
			if(i>=b)return false;
			j=ind[i].startpos;
			while(j<n&&ST[j].key<=ind[i].maxkey)
			{if(ST[j].key==key) return true; j++; }
	return false;
	}
}

3.5性能(特点)

空间开销:需要储存索引的辅助数组。
该方法的平均时间复杂度为Θ(logn),最差时间复杂度是Θ(n)。

3.6备注

分块查找由于只要求索引表是有序的,对块内节点没有排序要求,因此特别适合于节点动态变化的情况。当增加或减少节以及节点的关键码改变时,只需将该节点调整到所在的块即可。

二、基于树形结构的查找方法

1.BST树查找

1.1查找表结构特点

BST或者是空树或者是一棵满足下列性质的二叉树。
1.若左子树不为空,则左子树上所有结点的值都小于根结点的值;
2. 若右子树不为空,则右子树上所有结点的值大小于根结点的值;
3.左右子树都分别是BST树。

1.2查找基本思想

首先将给定的k值与根结点的关键字进行比较,若相等则查找成功.
a) 给定的k值小于BST的根节点的关键字:继续在该节点的左子树进行查找;
b) 给定的k值大于BST的根节点的关键字:继续在该节点的左、右子树进行查找。

1.3步骤

从根结点开始进行查找:
1、如果结点为空,结束查找;
2、如果两值相等,返回查找成功;
3、如果该结点值小于待查找值,返回该结点的右子树,否则返回该结点的左子树;
重复步骤123,直到查找成功或者查找不成功。

1.4核心伪代码

1.递归算法

BSTNode *BST_search(BSTNode *T,Keytype k)
{ if(T==NULL) return(NULL);
 else{
  if(T->key==k) return (T);
  else if(k<T->key) 
  {return(BST_search(T->Lchild,k));}
  else  
    return(BST_search(T->Rchild,k));
}

2.非递归算法

BSTNode *BST_search(BSTNode *T,Keytype k)
{ BSTNode p=T;
 while(p!=NULL&&p->key!=k)
 {
   if(k<p->key) p=p->Lchild;
   else p=p->Rchild;
   if(p->key==k) return p;
   else return NULL;
 }
}

1.5性能(特点)

最差情况下BST查找与其深度有关,故时间复杂度为O(logn)

1.6备注

2.AVL树查找

2.1查找表结构特点

1.AVL是一棵满足BST特性的二叉树;
2.AVL树中每个结点的平衡因子(某结点左右子树高度差)的绝对值不超过一;
3.每个结点保存集合中的一个数据;
4.一棵n个结点的AVL树深度最大为O(logn);
5.AVL的查找、插入和删除操作的时间复杂度为O(logn).

2.2查找基本思想

与BST树查找基本思想一致

2.3步骤

与BST树查找步骤一致

2.4核心伪代码

与BST树查找步骤一致

2.5性能(特点)

最差时间按复杂度是O(logn)

2.6备注

AVL树的策略是出现不平衡就调整使他平衡;
AVL树查找适合做内存的检索;

3.B树查找

3.1查找表结构特点

1.B树是一棵多叉平衡树;
2.每个结点保存集合中的多个数据;
3.集合中的数据有可比较的关键码;
4.B树中结点储存的数据之间满足BST特性;
5.B树的树结构总是高度平衡的,它的所有叶结点都在同一层。

3.2查找基本思想

从根节点开始:
1.在当前结点中对记录进行搜索。如果找到带有检索关键码的记录,那么就返回这条记录。入锅当前结点是叶结点,而且没有找到关键码,返回检索失败。
2.否则,沿着正确的分支重复这一过程。

3.3步骤

1.从根结点开始进行查找;
2.在结点内找到最后一个小于等于待查找值的关键字,若相等则查找成功,否则顺着指针找到下一结点;
3.重复第二步,直到结点为空,返回查找失败。

3.4核心伪代码

Typedef struct{
 BTNode *pt;//指向找到的结点
 int i;//在结点中的关键字序号
 int tag;//是否查找成功
}Result;
Result SearchBTree(Btree T,Keytype k)
{//在m阶B树上查找k,若查找成功,则tag为1,指针pt指向所指结点中第i个关键字。
p=T; q=NULL; found=false; i=0;
while(p!=NULL&&!found) {
 i=Search(p,k);
//在p->key[1..keynum]中查找
//i使得p->key[i]<=k<p->key[i+1]
 if(i>0&&p->key[i]==k)found=true;
 else {q=p;p=p->pri[i];}
  }
if(found) return(p,i,1);
else return(q,i,0);
}

3.5性能(特点)

平均情况和最差情况下时间复杂度都为Θ(logn)。

3.6备注

1.B树特别适合基于磁盘的检索;
2.B树自始至终都是平衡的;
3.该方法可适用于大规模数据;

4.Trie树查找

4.1查找表结构特点

Trie树:
1.它是一棵多岔有序树;
2.根节点不储存信息
3.根节点到标记为真的节点经过的节点字符组成的字符串表示一个关键字
4. 标记为真的结点还可以包含指向指向该关键字记录的指针
5.每个节点的所有子节点之间包含的字符都不同。

4.2查找基本思想

从Trie树的根节点开始出发,沿和给定值相应的结点逐层向下,直到给定值的最后一项或叶子结点。
若到了叶子结点,其中的关键字和给定值相等,则查找成功;
若到了给定值的最后一项且此时的结点是真的,查找成功;其余情况查找失败。

4.3步骤

  1. 当前结点设为Trie树的根节点,令i=0;
  2. 根据给定字符串中的字符s[i],找到Trie树对应的孩子的位置,若为空返回查找失败;
  3. 将当前节点设为对应的孩子结点,i++,继续执行步骤2,若字符串结束,当前结点标记为假,则返回查找失败,否则返回查找成功。

4.4核心伪代码

//在Trie树中查找一个字符串
bool search(string s)
{
TrieNode p=root;
for(int i=0;i<s.length();i++){
int index=s[i]-‘a’;
if(p.children[index]==null)
{return false;}
p=p.children[index];
}
if(p.isEnding==false)
{return false;}
else return true;
}

4.5性能(特点)

字典树查找字符串的时间复杂度是O(k),k代表字符串的长度。

4.6备注

1.Trie树不适合精确匹配查找,适合查找前缀匹配的字符串;
2.Trie树特别适合用于统计和排序大量的字符串

三、基于计算的查找方法

1.散列查找

1.1查找表结构特点

散列表,通过散列函数把元素的键值映射成某一位置直接进行访问,其物理存储结构是数组,利用的是数组支持按照下标进行随机访问的特性。

1.2查找基本思想

将键码的某些信息打乱映射到某一位置,使用键码部分信息找到对应的位置,从而进行查找

1.3步骤

  1. 首先在元素的关键字k和储存位置p之间建立一个对应关系h,使得h(k)=p;
  2. 通过散列函数h创建散列表,如果需要的话,使用冲突解决策略;
  3. 利用p=h(k),找到关键字为k的位置p,从p开始,或者使用冲突解决策略找到包含关键字k的元素,比较两个元素,若相等,查找成功,若不相等,查找失败。

1.4核心伪代码

bool hash_search(Elem a[ ],
Elem key)
{
  int p=hash(key);
  if (a[p]==key) return true;
  return false;
}

1.5性能(特点)

平均时间复杂度是O(1);最差情况下时间复杂度是O(n)。

1.6备注

  1. 散列方法适合精确查找,不适合范围查找;
  2. 当数据具有多维性、关键字不唯一、前缀搜索时关键字很长、动态的、需要排序时,该方法不适用;
  3. 散列查找的核心是实现散列表,要从以下三个方面来设计:a.设计一个合适的散列函数b.选择合适的散列冲突解决方法c.定义装载因子阈值,设计动态扩容策略。
  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值