1 / 71

计算机软件基础 The software basic of computer 主讲:刘志强 西安交通大学 计算机教学实验中心

第 6 单元 查找. 计算机软件基础 The software basic of computer 主讲:刘志强 西安交通大学 计算机教学实验中心. 教学目标. 了解有关查找的 基本概念 查找的主要算法. 教学要求. 通过本单元的学习,了解、掌握有关查找的: 基本概念 查找、平均查找长度 主要查找算法 顺序查找、折半查找、分块查找 树表查找、哈希查找. 本单元涉及的内容. 第 3 章 3.1 什么是查找 3.2 顺序表查找 3.3 树表查找 3.4 哈希查找 P90 ~P102. 一、基本概念. 查找 查找表 静态查找

amie
Download Presentation

计算机软件基础 The software basic of computer 主讲:刘志强 西安交通大学 计算机教学实验中心

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第6单元 查找 计算机软件基础 The software basic of computer 主讲:刘志强 西安交通大学 计算机教学实验中心

  2. 教学目标 • 了解有关查找的 • 基本概念 • 查找的主要算法

  3. 教学要求 通过本单元的学习,了解、掌握有关查找的: • 基本概念 • 查找、平均查找长度 • 主要查找算法 • 顺序查找、折半查找、分块查找 • 树表查找、哈希查找

  4. 本单元涉及的内容 • 第3章 • 3.1 什么是查找 • 3.2 顺序表查找 • 3.3 树表查找 • 3.4 哈希查找 • P90~P102

  5. 一、基本概念 • 查找 • 查找表 • 静态查找 • 动态查找 • 平均查找长度

  6. 查找 • 查找就是在给定的DS中找出满足某种条件的结点;若存在这样的结点,查找成功;否则,查找失败。 • 查找表是一组待查数据元素的集合。 • 静态查找是仅仅进行查询和检索操作,不改变查找表中数据元素间的逻辑关系的查找。 • 动态查找 是除了进行查询和检索操作外,还对查找表进行插入、删除操作的查找,动态地改变查找表中数据元素之间的逻辑关系。

  7. n ASL =  Pi* Ci i=1 n Pi = 1 i=1 平均查找长度 • 平均查找长度 (ASL-Average Search Length) 在查找过程中,对每个结点记录中的关键字要进行反复比较,以确定其位置。因此,与关键字进行比较的平均次数,就成为平均查找长度。它是用来评价一个算法好坏的一个依据。 • 对含有n个数据元素的查找表,查找成功时的平均查找长度为: 其中:Pi 为查找表中第i个数据元素的概率,且 Ci为查找第i个数据元素时需比较的次数。 显然,Ci随查找过程及DS的不同而各异。

  8. 二、主要查找算法 • 顺序查找 • 折半查找 • 分块查找 • 树表查找 • 哈希查找

  9. 1、顺序查找 • 算法思想: 最古老的算法。从第1个元素到最后1个元素,逐个进行比较。 • 顺序查找是最简单、最普通的查找方法。 • 查找表的存储结构: • 既适用于顺序存储结构 • 也适用于链式存储结构

  10. 算法描述 • 查找操作步骤: • step1从第1个元素开始查找; • step2用待查关键字值与各结点(记录)的关键字值逐个进行比较;若找到相等的结点,则查找成功;否则,查找失败。

  11. 顺序查找算法框图 开始 seq_search(A,n,key) A 待查表 n 元素个数 key 要找的值 i=0 查找key的循环 i++ Y i<n&&A[i]!=key? N N Y A[i]==key? 显示“查找失败” 显示“查找成功” 返回

  12. 顺序查找算法3-1 seq_search(item , n , key ) int *item ,n , key ; { int i=0 ; while ( i < n && item[i] != key ) i++; /* 查找key的循环 */ if (item[i]= = key ) { printf(“查找成功 !\n”); return (i); } else { printf(“查找失败 !\n”); return (-1);} } 示例

  13. 改进顺序查找算法框图 开始 s_search_a(A,n,key) i=0 ; A[n]=key 设置哨兵 查找key的循环 i++ Y A[i]!=key? N N Y i < n? 显示“查找失败” 显示“查找成功” 返回

  14. 顺序查找算法3-2(改进算法) seq_search_adv(item , n , key ) int *item ,n , key ; { int i=0 ; item[n]=key ; /* 设置哨兵 */ while ( item[i]!= key ) i++; /* 查找key */ if ( i< n ) /* 如果 i = n,没找到 */ { printf(“查找成功 !\n”); return (i); } else { printf(“查找失败 !\n”); return (-1); } } 注: 顺序查找算法中,执行频率最高的是while语句,改进后,可以节省近一半的时间。

  15. 顺序查找算法主程序 #include “stdio.h” #define n 7 main() { int key,loc=0; int a[10]={43,15,21,37,2,5,82}; printf(“Input key:”); scanf(“%d”,&key); loc=s_search_adv(a,n,key); if (loc >0) printf(“loc=%d,key=%d\n”,loc,key); } 示例

  16. n n n+1 1 ASL =  Pi*Ci =  (n-i+1) = n 2 i=1 i=1 n ASL  2 算法讨论 • 平均查找长度ASL在等概率的情况下 • 平均查找长度ASL在等概率的情况下 • 优点: • 对结点的逻辑次序(不必有序)和存储结构(顺序、链表均可)无要求; • 当序列中的记录“基本有序”或N值较小时,是较好的算法; • 缺点: • ASL较长 • 讨论:能否减少比较次数,以提高效率。 • 例如,…… 二分法等

  17. 2、折半查找 • 算法思想: 将有序数列的中点设置为比较对象,如果要找的元素值小于该中点元素,则将待查序列缩小为左半部分,否则为右半部分。 即通过一次比较,将查找区间缩小一半。 • 二分查找是一种高效的查找方法。它可以明显减少比较次数,提高查找效率。但是,二分查找的先决条件是查找表中的数据元素必须有序。

  18. 算法描述 • 算法步骤: • step1首先确定整个查找区间的中间位置, mid = ( left + right )/ 2 • step2用待查关键字值与中间位置的关键字值进行比较; • 若相等,则查找成功; • 若大于,则在后半区域继续进行二分查找; • 若小于,则在前半区域继续进行二分查找。 • Step3对确定的缩小区域再按二分公式,重复上述步骤; • 最后,得到结果: • 要么,查找成功, 要么,查找失败。 • 存储结构 • 用一维数组存放。

  19. 折半查找算法举例 • 对给定数列(有序){ 3,5,11,17,21,23,28,30,32,50},按折半查找算法,查找关键字值为30的数据元素。 第1次: { 3,5,11,17,21,23,28,30,32,50 } mid1= (1+10)/2 = 5 第2次: { 23,28,30,32,50 } mid2 = (6+10) /2 = 8 left mid right left right mid

  20. 折半查找算法3-3 bin_search ( item , n ,key ) int *item, n, key; { int left ,right , mid; left=0; right = n-1; while ( left  right ) { mid = ( left + right )/2 ; /* 计算中点位置 */ if ( key < item[mid]) right = mid - 1; /* 待查区间在左部 */ else if (key > item[mid]) left = mid + 1; /* 待查区间在右部 */ else{ printf ( “ Successful search\n”); return mid ; /* 查找成功 */ } printf( “ Search failure \n”); return -1; /* 查找失败 */ }

  21. 折半查找算法3-3主程序 #define “stdio.h” int num; main( ) { int res, key ; int s[10]={1,3,5,7,9,11,13,15,17,19,21,23}; res=b_search(s,12,7); if(res>0) printf("res=%d , num=%d\n",res+1,num); else printf(“search failure\n”); } 示例

  22. 算法讨论 • 优点: ASL  log2n;即每经过一次比较,查找范围就缩小一半。经log2n 次计较就可以完成查找过程。 • 缺点:因要求有序,所以对所有数据元素按大小排序是非常费时的操作。另外,顺序存储结构的插入、删除操作不大便利。 • 考虑: • 能否一次比较抛弃更多的部分(即一次比较,使查找范围缩得更小),以达到提高效率的目的; • ……? • 把两种方法(顺序查找和二分查找)结合起来,即取顺序查找简单和二分查找高效之所长,来达到提高效率的目的?

  23. 3、分块查找 • 分块查找又称索引顺序查找,这是顺序查找的一种改进方法。 • 方法描述:将n个数据元素“按块有序”划分为m块(m  n)。每一块中的结点不必有序,但块与块之间必须“按块有序”;即第1快中任一元素的关键字都必须小于第2块中任一元素的关键字;而第2块中任一元素又都必须小于第3块中的任一元素,……。每个块中元素不一定是有序的。

  24. 分块查找算法描述 • step1 先选取各块中的最大关键字构成一个索引表; • step2 查找分两个部分: • 先对索引表进行二分查找或顺序查找,以确定待查记录在哪一块中; • 在已确定的块中用顺序法进行查找。

  25. 22 33 48 12 42 List[1] 22 60 13 44 58 44 List[2] 9 38 74 List[3] 74 24 8 47 分块查找举例 • 有数列如下: { 22,12,13,9,8,33,42,44,38,24,48,60,58,75,47} 按“块有序”分三块:(22,12,13,9,8),(33,42,44,38,24), (48,6,58,74,47)。选取每块中最大的关键字组成索引表[22,44,74],查找关键字值为60的元素。 • 用二分法,确定在索引表中的位置为 mid=2,key值60与a[2]比较,60>a[2],取第3个块;在第3块中用顺序法查找,比较两次,就可以找出60的元素来。

  26. 索引表结构定义 #include "stdio.h" typedef struct { int key; /* 块最大值 */ int link; /* 指向块入口地址 */ } index;

  27. 分块查找逻辑框图 i_s_search(ls[],s[],m,key,l) ls[] 索引表 S[] 待查表 M 块数 key 要找的值 l 块长度 开始 i=0 确定块的循环 i++ Y i<m 且 key>ls[i].key? N N Y i ≥ m? 块入口地址 j=ls[i].link 显示“查找失败” 返回 块内查找循环 j++ Y N key!=s[j]且j在范围内? N Y key=s[j]? 查找失败 查找成功 返回

  28. index_seq_search.c子函数 index_seq_search(index ls[],int s[],int m,int key,int l) { int i,j; i=0; while(i<m && key>ls[i].key) i++; /* 确定在哪块查找 */ if(i>=m) { printf(“ Searching failure\n"); return(-1); } else /* 否则,查找成功处理 */

  29. 分块查找子函数(续) { j=ls[i].link; /* 块入口地址 */ while (key !=s[j] && (j-ls[i].link)<l) j++; if(key==s[j]&&(j-ls[i].link)<l)/* 查找成功*/ { printf("Successful search\n LOC(s[%2d])=%d\n",j,s[j]); return(j); } else /* 查找失败 */ { printf("Searching failure\n"); return(-1); } } } /* 结束 */

  30. 分块查找主函数 main() { index ls[5]={ 14,0,34,5 ,66,10,85,15,100,20} ; int a[]={8,4,3,2,14, 34,20,17,28,29 ,58,61,59,66,48, 81,80,79,83,69,89,100,96,86,87};int i,j=0,key; for(i=0;i<25;i++) { if (j==0) printf("{ "); if (j==5) { printf(" }"); j=0; printf(" {"); } printf("%4d",a[i]); j++; } printf(" } \n"); printf("Enter key: "); scanf("%d",&key); index_seq_search(ls,a,25,key,5); } 示例

  31. 算法讨论 • 设索引表使用二分法,则有: ASL  log2(n/S +1)+ S/2 其中:n为表长,S为块长(假设各块长度相等)。 • 优点: 插入、删除操作方便;只要找到对应的块,在块中任意位置操作均可。 • 缺点: 索引表增加了辅助存储空间。 注: 索引表在数据库系统中广泛使用。 • 还有什么方法吗? 树表查找

  32. 4、树表(二叉排序树)查找 • 前三种查找方法各有千秋。二分法查找效率高,顺序法可以采用链表存储结构,操作灵活。 但最好是既有二分法的高效率,又有链表灵活性的查找方法。 • 二叉排序树实际上就是将数据元素组织成二叉树形式,以达到与二分法相同的查找效率,而又具有链表的插入、删除操作的灵活性。

  33. 二叉排序树查找(算法3-4) • step1首先建立起二叉排序树。 • step2将待查关键字值与树根结点进行比较,若相等,查找成功; • step3否则根据比较结果确定查找路径: • 若小于根结点的关键字值,则与左子树的根结点的关键字值进行比较; • 若大于等于根结点的关键字值,则与右子树的根结点的关键字值进行比较。 • step4重复上述步骤,直到要么找到,查找成功;要么找不到,查找失败。

  34. 存储结构描述 二叉排序树结点结构: struct tree { char info; struct tree *left; struct tree *right; }

  35. 二叉排序树生成算法

  36. 主程序框图 开始 初始化 输入结点数据循环 !ROOT root=create_btee() create_btree() N 结束? Y Print_btree() 打印该树 Search_btree() 查找指定结点

  37. 生成二叉排序树程序框图 create_btree( root,r,info) root 根指针 r 插入的结点 info 要插入的结点值 开始 Y 申请结点空间 r = 0? 根结点的处理 N 非根结点 Y N Y info<r->info? r = 0? 显示“溢出” t=r->left N t=r->right 结束 r->left = 0; r->right = 0; r->info = info ; 调用本函数 Y N root? root->left=r 或 root->right=r r->left=0 r->right=0 返回

  38. 查询二叉排序树算法框图 Search_btree(root,key) root 根指针 key 要找的值 开始 Y 显示“空树” !root N root->info!=key循环 返回 key<root->info? root=root->left root=root->right N N Y root=0? 循环结束? 显示“失败” Y root!=0? 查找成功,显示 返回

  39. 打印算法框图 开始 print_btree(root,l ) root 根指针 l 起始点距离 Y r=0? N 调用自身打印左子 打印当前结点值 调用自身打印右子 返回

  40. 主程序Btree.C #include “stdio.h” struct tree { char info; struct tree *left,*right; } main ( ) { char *s,*c,key=‘’; struct tree *create_btree(),*search_btree(),*root=0; do { printf(“Enter a letter:”); gets(s); if (!root) root=create_btree(root,root,*s); else create_btrr(root,root,*s); } while (*s) ;

  41. 主程序Btree.C(续) print_btree(root,0); key=‘1’; while ( key) { printf(“Enter a key to find:”); scanf(“%s”,&c); key=search_btree(root,c); printf(“press to continue\n”); } } /* Btree.C 结束 */

  42. 生成二叉排序树程序 struct tree create_btree(root,r,info) struct tree *root,*r; char info; { if (r = = 0 ) { r=malloc(sizeof(struct tree)); if ( r = = 0) { printf(“Out of memory\n”); exit(0); } r->left= 0; r->right=0; r->info=info; if (root) { if(info<root->info) root -> left=r; else root->right=r; } else { r->right=0; r->left = 0; } return r; } /* if = = 0 接下页 */

  43. 生成二叉排序树程序(续) if (info < r->info) create_btree(r,r->left,info); if(info>=r->info) create_btree(r,r->right,info); } /* create_btree(root,r,info) */

  44. 打印二叉排序树程序 print_btree(r,l) struct tree *r; int l; { int i; if (r = = 0) return ; print_tree(r->left,l+1); for(i=0;i<l;i++) printf(““); printf(“%c\n”,r->info); print_btree(r->right,l+1); }

  45. 查询二叉排序树程序 struct tree *search_btree(root,key) struct tree *root; char key; { if (!root) { printf(“Emptu btree\n”);return root; } while(root->info!=key) /* 查找key 的循环 */ { if(key<root->info) root=root->left; /* 沿左路查找 */ else root=root->right; /* 沿右路查找 */ if(root= =0) /* 到叶结点也没找到 */ { printf(“Search Failure\n”); break ; } } if (root !=0) /* 查找成功 */ printf(“Successful search\n key=%c\n”,root->info); return root ; } 示例

  46. 程序输入 输入: 输出: h  b d  d p  e r  h b  p e  r 

  47. 10 18 3 4 13 25 9 举例 • 对数列{10,18,3,4,9,13,25},生成二叉排序树如右;查找关键字值25。 • 25比较根结点值10,走右路,再与18进行比较,走右路,最后与25进行比较,相等,查找成功。比较了3次。 • 若查找35,则与10、18、25 分别进行比较后仍没找到相等 元素,查找失败,也比较了三次。

  48. 算法讨论 • 二叉排序树查找的 ASL  log2n。若其平衡特性较好的话,ASL与折半查找相同。 • 二叉排序树是动态生成的,其特性随插入结点的先后次序的不同而改变,为防止其蜕化为单枝树,要进行平衡化处理。 • 二叉排序树因采用链表结构,需要辅助存储空间。 • 上述方法都是建立比较基础上的,还有其它类型的方法吗?

  49. 5、哈希(hash)查找 • 哈希查找也称为散列查找。它不同于前面介绍的几种查找方法。上述方法都是把查找建立在比较的基础上,而哈希查找则是通过计算存储地址的方法进行查找的。 • 计算是计算机的特点之一,因此,建立在计算基础上的哈希查找是一种快速查找方法。

  50. 哈希查找的基本概念 • 哈希表 由哈希函数的值组成的表。哈希查找是建立在哈希表的基础上,它是线性表的一种重要存储方式和检索方法。在哈希表中可以实现对数据元素的快速检索。 • 哈希函数 哈希表中元素是由哈希函数确定的。将数据元素的关键字K作为自变量,通过一定的函数关系(称为哈希函数),计算出的值,即为该元素的存储地址。表示为: Addr = H(key) • 建立哈希函数的原则 • 均匀性 H(key)的值均匀分布在哈希表中; • 简单 以提高地址计算的速度。

More Related