1. 数据的组织和查找是大多数应用程序的核心
2. 线性表、树、图是数据的组织结构
3. 查找是所有数据处理中最基本、最常用的操作
4. 当在一个庞大数量的数据集合中查找时,查找方法和效率就显得格外重要
1. 查找包含四种操作:查询、检索、插入、删除
查询,元素是否存在
检索,找到某个元素,访问元素的属性
插入,若元素不存在则插入
删除,若元素存在则删除
2. 静态查找表:包含前两种查询和检索操作,查找操作不影响原有数据集合
3. 查找的术语
查找表,同一类型元素构成的集合。集合是一个松散灵活的数据结构
关键字,是数据元素中某个数据项的值,用以标识一个数据元素,分主关键字(唯一标识),次关键字(部分识别)
查找,根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素(或记录)。
若查找成功返回位置或记录;查找不成功返回空指针或空记录
4. 衡量查找算法的标准
时间复杂度
空间复杂度
平均查找长度ASL,为确定记录在表中的位置所进行的和关键字比较的次数的平均值
n为查找表的长度,即表中所含元素的个数
Pi为查找第i个元素的概率(∑Pi=1)
Ci是查找第i个元素时同给定值K比较的次数
1. 顺序查找,是顺序表的查找方法,以顺序表或线性链表表示静态查找表。
①.从表中最后一个记录开始
②.逐个进行记录的关键字和给定值的比较
③.若某个记录比较相等,则查找成功
④.若直到第1个记录都比较不等,则查找不成功
2. 实现代码
//顺序查找带哨兵
void search(int *a,int n)
{
a[0]=n;
for(int i=l;i>=0;i--)
{
if(a[i]==n)
{
if(i>0)
cout<
3. 顺序查找算法性能
对顺序表而言,Ci=n-i+1
在等概率查找的情况下,Pi=1/n
ASL=n*P1 +(n-1)P2 +…+ 2Pn-1+ Pn = (n+1)/2
4. 顺序查找算法优化
如果被查找的记录概率不等时,设
Pn≥Pn-1≥···≥P2≥P1
记录按照概率来排列,这样使得ASL可以达到极小值
若查找概率无法事先测定,增加一个访问频度域存储访问频率,然后记录按照访问频率来排序
在每次查找之后,将刚刚查找到的记录直接移至表尾的位置上。
5. 其他
顺序查找算法优点:简单、适应面广(对表的结构无任何要求)
顺序查找算法缺点:平均查找长度较大
特别是当n很大时,顺序查找效率很低
1. 折半查找算法是有序表的查找方法
在折半查找算法中,静态查找表按关键字大小的次序,有序地存放在顺序表中
2. 折半查找的原理是:
先确定待查记录所在的范围(前部分或后部分)
逐步缩小(一半)范围直到找(不)到该记录为止
3. 折半查找算法设计
1.n个对象从小到大存放在有序顺序表ST中,k为给定值
2.设low、high指向待查元素所在区间的下界、上界,即low=1, high=n
3.设mid指向待查区间的中点,即mid=(low+high)/2û
4.让k与mid指向的记录比较
若k=ST[mid].key,查找成功
若k 若k>ST[mid].key,则low=mid+1 [下半区间] 5.重复3,4操作,直至low>high时,查找失败。 4. 算法代码实现 5. 算法性能分析 6. 其他 折半查找算法优缺点 折半查找的效率比顺序查找高(特别是在静态查找表的长度很长时) 查找只能适用于有序表,并且以顺序存储结构存储。 折半查找前要先排序 1. 索引顺序查找,又称分块查找,是一种索引顺序表(分块有序表)查找方法,是折半查找和顺序查找的简单结合 要求顺序表是分块有序表,将整个表分成几块,块内无序,块间有序 所谓块间有序是指后一块表中所有记录的关键字均大于前一块表中的最大关键字 2. 索引顺序查找包含主表和索引表 主表:用数组存放待查记录,每个数据元素都含有关键字域 索引表:索引表是按关键字有序的,每个结点含有最大关键字域和指向本块第一个结点的指针 3. 索引顺序查找算法设计 用折半或顺序查找方法,在索引表中找到块 用顺序查找方法,在主表对应块中找到记录 4. 算法代码实现 5. 算法性能分析 若将长度为n的表分成b块,每块含s个记录,表中每个记录查找概率相等 顺序查找 折半查找 分块查找 ASL 最大,(n+1)/2 最小,log2(n+1)-1 两者之间 表结构 有序表、无序表 有序表 分块有序表 存储结构 顺序存储结构 线性链表 顺序存储结构 顺序存储结构 线性链表 1. 查找的概念 包含四种操作:查询、检索、插入、删除 包含前两种操作的是静态查找,包含四种操作的是动态查找 评价查找算法的指标平均查找长度ASL 2. 静态查找表:顺序查找、折半查找、顺序索引查找,位置从1开始 3. 顺序查找:带哨兵的查找,从末尾往前找;可以是顺序表或链表 ASL=(n+1)/2,时间复杂度O(n), 4. 折半查找:又称二分查找,要求表有序且必须是顺序表 每次找中点比较,查找范围缩小一半 ASL=Log2(n+1)-1,时间复杂度O(log2n) 5. 顺序索引查找:又称分块查找,要求块间有序块内无序;可以是顺序表或链表 要求有索引表,对主表进行分块并建立索引 先用折半查找搜索索引表,再用顺序查找搜索块内 1. 一个有100个元素的线性表,若采用带哨兵的顺序查找某个元素,最少_____次比较,最多_____次比较 2. 已知顺序表{2,4,5,8,12,14,24,36,98},若采用二分查找,比较次数最多的元素是____;若查找元素24,经过比较的元素是____ 3. 已知顺序表{102,114,105,218,202,243,318,306,384,352},如果按数据的百位数进行分块,采用索引顺序查找,则查找元素384,经过比较的元素是__________ //折半查找
void search(int *a,int n) {
int left = 1;
int right = l;
while (left <= right) {
int mid = (left + right) / 2;
if (a[mid] < n)
left = mid + 1;
else if (a[mid] > n)
right = mid - 1;
else {
cout << mid << endl;
return;
}
}
cout << "error" << endl;
}
/*
折半查找算法性能分析
设有序表的长度n=2h-1(即h=log2(n+1)),则描述折半查找的判定树是深度为h的满二叉树
树中层次为1的结点有1个,层次为2的结点有2个,层次为h的结点有2h-1个
假设表中每个记录的查找概率相等,则查找成功时折半查找的平均查找长度
_=1/ ∑_(=1)^▒_ =1/ [∑_(=1)^ℎ▒〖×2^(−1) 〗]=(+1)/ log_2( +1)−1
*/
索引顺序查找
//分块查找
void search()
{
int n;
cin >> n;
int a[n];
for (int i = 0; i < n; i++) {
cin >> a[i];
}
int m;
cin >> m;
int max[m];
int index[m + 1];
for (int i = 0; i < m; i++) {
cin >> max[i];
}
int x = n / m;
index[0] = 0;
for (int i = 1; i < m; i++) {
index[i] = index[i - 1] + x;
}
index[m] = n ;
int t;
cin >> t;
while (t--) {
int k;
cin >> k;
int num = 0;
int visit = 0;
for (int i = 0; i < m; i++) {
num++;
if (k <= max[i]) {
for (int j = index[i]; j < index[i + 1]; j++) {
num++;
if (k == a[j]) {
visit = j;
goto out;
}
}
}
}
out:
if (visit != 0) {
cout << visit + 1 << "-" << num << endl;
} else {
cout << "error" << endl;
}
}
}
/*
索引顺序查找算法性能
若将长度为n的表分成b块,每块含s个记录,表中每个记录查找概率相等
用折半查找方法在索引表中查找索引块
ASL块间≈log2(n/s+1)
用顺序查找方法在主表对应块中查找记录,
ASL块内=(s+1)/2
ASL分块查找=log2(n/s+1)+(s+1)/2
索引顺序查找应用的隐含条件:主表数据要块间有序。如果主表完全无序,还是要用顺序查找。
*/
静态算法比较
总结
练习