数据结构常用算法分析(C++版)-8大查找

简介

写这一节,其实一开始我是拒绝的,因为我感觉在本科的时候没怎么学呀!不过后来想了想,“Duang!”一下,发现我错了, 查找在数据库上有辣么重要的应用,还是写出来吧!不写完,总感觉《数据结构》总结的不是很完整!

另外话说,我当时去哪玩去了?是骗小女生去了?不应该呀,我这么善良的宝宝~

好了,收!

这节呢,就讨论一下8种常用的查找算法,部分有代码实现,一起来看看吧! 相关代码已经托管到Github上了~我是代码,快点我

基础知识:

查找分类

  • 静态查找和动态查找(动态查找对查找表有删除和插入操作)
  • 无序查找和有序查找(要求查找数列是否必须有序)

平均查找长度(Average Search Length,ASL)计算方法:ASL = (Pi*Ci的和)

8大查找算法

静态查找

1:顺序查找

顺序查找对查找表无要求,查找过程依次遍历数组元素,进行对比后返回~

2:二分查找

二分查找,要求数组必须有序,通过不断的折半查找所需元素,最多比较次数((log2n)向下取整+1) 具体实现,有递归和非递归2种形式,下面是非递归的形式!

源代码如下:


int binarySearch(vector<int> &v,int m)
{
	int mid=0;
	int low=0;
	int hight=v.size()-1;
	while(low<=hight)
	{
		mid=(low+hight)/2;
		if(v[mid]==m)break;
		if(v[mid]<m)
			low=mid+1;
		else
			hight=mid-1;
	}

	if(v[mid]==m)
	{
		print(v,m,true);
		return m;
	}
	else
	{
		print(v,m,false);
		return -1;
	}
}

3:斐波那契查找

斐波那契查找利用黄金分割的原理,遵照数据的非均匀分布的现象!

使用有2个条件要求

  • 数组大小要是某一个斐波那契数
  • 数组要是有序数组

int initfb(vector<int> &v,int m)
{
	int s=0;
	int f=1;
	int i=0;
	v.push_back(s);
	while(i++<m)
	{
		f=f+s;
		s=f-s;
		v.push_back(f);
	}
	cout<<"创建斐波那契序列:"<<endl;
	for(vector<int>::iterator it=v.begin();it!=v.end();it++)
		cout<<*it<<" ";
	cout<<endl;
	return 0;
}

int fbSearch(vector<int> &v,int m)
{
	vector<int> fb;
	initfb(fb,10);
	int mid=0;
	int low=0;
	int hight=v.size()-1;
	int i=4;
	v.pop_back();v.pop_back();
	while(low<=hight)
	{
		mid=low+fb[i];
		if(v[mid]==m)break;
		if(v[mid]<m)
		{
			low=mid+1;
			i-=2;
		}
		else
		{
			hight=mid-1;
			i--;
		}
	}
	if(v[mid]==m)
	{
		print(v,m,true);
		return m;
	}
	else
	{
		print(v,m,false);
		return -1;
	}
}

4:索引顺序表查找

索引顺序表查找是对顺序查找和二分查找的结合,通过索引-数组的关系来维护,要求部分有序,即数组内部无序,数组之间有序!

算法步骤如下:

  • 选取各块中的最大关键字组成索引表;
  • 对索引表进行二分查找或顺序查找,确定在哪个块中;
  • 在已确定的块中用顺序法进行查找。

动态查找

5:二叉排序树(BST)

也叫二叉查找树,左小、右大!

二叉排序树定义:

  • 左子树:不为空,则小于根结点的值
  • 右子树:不为空,则大于根结点的值
  • 左右孩子分别为二叉排序树

二叉搜索树的操作:(利用树的递归定义的性质)

查找: 如果值大于根节点,着查找右孩子,否则查找左孩子,递归下去。

插入: 先查找,如果值大于返回结点,则插入右孩子,否则插入左孩子。

删除: 右孩子为NULL,直接赋值左孩子;左孩子为NULL,直接赋值右孩子;均不为NULL,找到左孩子的最大右孩子,置换,重接终端结点

6:平衡二叉树(AVL树)

定义:

平衡因子BF只能取 -1,0,1 即AVL树上任何结点的左右子树的深度之差不能超过1

平衡二叉树的方法:

  • 单向右旋
  • 单项左旋
  • 双向旋转 先左后右,转化为1
  • 双向旋转 先右后左,转化为2

7:B-树与B+树

B-树:(m阶)

  • 每个结点最多m棵子树;
  • 根节点不是叶结点,至少有2棵子树
  • 除根外,所有非终端结点至少m/2向上取整棵子树
  • 结点结构(n,a1,k1,a2,k2,a3,k3,…,kn,an)
  • 所有叶子结点在同一层上

B-树的分裂:(母爱无私,兄弟奉献)(并不太懂)

B+树(这对文件系统而变种的B-树)

  • n棵子树的结点含有n个关键字;(B-树是N+1)
  • 所有叶子结点包含全部关键字,及指向关键字的指针,并且按照关键字大小顺序连接(B-树叶子结点只包含部分,且不相连)
  • 非终端结点是索引,包含子树中最大(小)的关键字(B-树非终端结点,比子树的最大(小)值要大(小))

8:哈希表

哈希表,散列,哈希地址,

冲突:将不同的关键字映射到同一Hash地址。冲突只能尽可能地减少,而不能完全避免

6种常用Hash算法:

  • 直接定址法 H=key 或者 H=a*key+b
  • 数字分析法 分析关键字的基,并选择冲突次数较少的基
  • 平方取中法 取关键字平方后的中间几位
  • 折叠法 关键字的基大致分布均匀,取几部分关键字的叠加和
  • 除留余数法 H=key % p
  • 伪随机数法

4种常用冲突解决方法:

  • 开放地址法 Hi=(H+d) % m (d 取值 线性探测,平方探测,伪随机数探测)
  • 再hash法 Hi=H(H)
  • 链地址法 (比较常用的Hash冲突解决方法)
  • 公共溢出区 填入策略不定

### 总结

这一节写的比较简单,只是介绍了相关的基础概念,很多代码都没有实现,以后回过来看的时候要记得补充呀!(^_^)

### 参考文献

7大查找算法

Search

    Post Directory