查找算法
查找分类:静态查找,动态查找
1.静态查找:顺序查找,二分查找,递归查找
2.动态查找:二叉排序树,散列表查找
顺序查找
就是从第一个开始遍历然后找出要查找的数
int find(int a[],int res)//传进去一个数组和要查找的数字
{
int k = a.length();//可能c++没有这个数组的长度的,但是差不多就是这个意思
int deng = -1;//记录查找的下标,先初始化为-1
for(int i = 0; i < k; i ++)
{
if(a[i] == res)
deng = i;
}
if(deng == -1)//没有找到
return 0;
else//找到了
return deng;
}
还有设置哨兵
int find(int a[],int res)
{
int i = a.length();
a[0] = res; //我们假设a[0]是没有元素的
while(a[i] != res)
{
i--;
}
return i;
}
相比于第一个只需要判断一次就可以,因为第一次for循环判断一次,if又判断一次
时间复杂度都是O(n)
二分查找
一般二分查找,都是整数二分
对了二分查找前提得是先有序,可以sort排序
int find(int a[], int res)
{
int k = a.length();
int l = 1;
int h = k;
low = (l + h) / 2;
while(l <= h)
{
if(mid == res)
{
return mid - 1;
}
if(mid < res)
{
l = mid + 1;
mid = l + h / 2;
}
if(mid > res)
{
h = mid - 1;
mid = l + h / 2;
}
}
return 0;
}
这个都是自己写的,比较繁琐,但是我感觉应该能看的明白
在书的195页还是建议找一个数组顺一顺,代码其实很容易懂
时间复杂度O(log2n)
//插值查找(优化的二分)
//和二分查找没有什么两样,就是mid的值是取中间的值
//然而插值查找是取res值大概占整个数组的多少比例
mid = l + (res - a[l])/(a[h] - l)*(h - l);
(res - a[l])分子
(a[h] - l) 分母
(res - a[l])/(a[h] - l)比例
(res - a[l])/(a[h] - l)*(h - l)站大致位置
时间复杂度O(log2n)
相对于数据增加差不多的
关于折半查找的ASL
ASL = (1/n)*(每个元素查到需要的次数)
n = 一共多少元素
折半查找相当于一个二叉树(不难想到嗷,想一想树的查找)
查到需要的次数也就是树的深度
这个博客写了ASL的查找方法
分块查找==索引排序查找
核心思想:块内无序,块间有序,可以找到每大块的最大值,从区间找,性能介于顺序查找和折半查找(可以说这个分块是先折半查找,在顺序查找,因为分块就相当于折半,遍历块相当于顺序查找)
算法:
建立索引表,包括两大内容,1.关键字(子表最大值)2.指针项(每一块的最开始位置)
ASL:
假设n个元素,分为b块,每块里面有k个元素
所以b = n / k, 总的ASL应该分为b的ASL和K的ASL,最后等于1/2*(n/k + k) + 1(实在是难写表达式p197有)
树表的查找
二叉排序树
void searchTree(Tree t,int key)
{
if(k == t->data.key || (!t))return t;
else if(k > t->data.key)return searchTree (t->lchild,k);
else if(k < t->data.key)return searchTree (t->rchilde,k);
}
就是一个递归的思想,如果key>data.key往右找,key<data.key往左找
可想而知最后的结果是中序遍历的结果,因为是树所以和二分时间复杂度一样都是O(log2n)
ASL也是同理
二叉排序树的插入
插入的基础上要有查找
void insertTree(Tree t,int key)
{
if(!t)
{
s = new TreeNode;
s->data = key;
s->lchild = s->rchild = null;
}
else if(key > t->data.key)
{
return insertTree(t->lchild,key);
}
else if(key < t->data.key)
{
return insertTree(t-<rchild,key);
}
}
这个实际上也是一个递归
二叉排序树的删除
分为三种,叶子,只有一颗子树,有两个子树
我们讲一下如果删除105该怎么办
因为是中序遍历,所以找直接前驱,让104补上去,然后103这个节点断了再补充到100的左边
平衡二叉树
定义:要么是一个空树,要么他的左子树和左子树都是平衡二叉树,且左子树和右子树的深度之差绝对值不超过1(还有二叉排序树,就是左子树小于右子树)
平衡因子:左子树和右子树的深度之差
平衡二叉树的平衡调整方法:
LL :左边多了,需要最右边的转下来,平衡一下平衡因子
RR :右边多了,需要最左边的转下来,平衡一下平衡因子
LR :首先先转R交换位置并于L一条线,然后变成LL线,同上了
RL:首先先转L交换位置并于R一条线,然后变成LL线,同上了
例题
还有一到十二月份的排序表
散列表(哈希表)查找
取别名,当时记得是找小姚明,学校名单没有小姚明,但是去了体育场发现了小姚明,因为打篮球打的好,所以起外号叫小姚明
(1)散列函数,散列地址:在存储key时候用函数H()计算出的地址p,p = H(key);
(2)散列表:连续的地址空间
构造散列函数
直接定址法:需要知道关键字的分布情况,这个表就是减去了1980得出来的(我感觉知道不知道的都是那么一回事)
数字分析法:
平方取中法:
折叠法:
除留余数法:
解决冲突的两种方法
1.地址开方法
H = (H(key) + d)%m
线性探测法d = 1 , 2 , 3 ...m - 1
二次探测法d = 1^2, -1^2,2^2, -2^2....K^2,-K^2(K<=m/2)
伪随机数法
2.链地址法

浙公网安备 33010602011771号