数据结构(21)--查找之静态查找表

来源:互联网 发布:汉诺塔递归算法 扩展 编辑:程序博客网 时间:2024/05/16 17:58

参考书籍:数据结构(C语言版)严蔚敏吴伟民编著清华大学出版社

1.静态查找表

    查找的定义:给定一个值k,在含有n个结点的表(或文件)中找出关键字等于给定值k的结点,若找到,则查找成功,输出该结点在表中的位置;否则查找失败,输出查找失败的信息。

    查找表是由具有同一类型(属性)的数据元素(记录)组成的集合。分静态查找表和动态查找表两类。
    静态查找表:仅对查找表进行查找操作,而不改变查找表中的数据元素;
    动态查找表:对查找表除进行查找操作外,可能还要进行向表中插入数据元素,或删除表中数据元素的表。

1.1.顺序查找

  查找过程:对给定的一关键字 K,从线性表(顺序表或线性链表均可以)的一端开始,逐个进行记录的关键字和 K 的比较,直到找到关键字等于 K 的记录或到达表的另一端。通常在线性表的0号单元存储key值以作为“哨兵”。

  监视哨作用:避免每步都去判断是否查找结束。

    测试用例:查找75和80


    代码实现:

package search;public class StaticSearch {/** * @param args *///在顺序表ST中顺序查找其关键字等于key的数据元素,若找到,则函数值为该元素在表中的位置,否则返回0public static int searchSeq(int[] st, int key){//st表的0号单元不使用//从后往前找,并在0号单元设置"监视哨"int i = st.length - 1;st[0] = key;//设置监视哨while(st[i] != key){i--;}return i;}public static void main(String[] args) {// TODO Auto-generated method stub//顺序查找测试int st[] = {0, 10, 20, 40, 80, 30, 60, 25};//0号单元不使用int key = 75;int result = searchSeq(st, key);if(result > 0)System.out.println("查找" + key + "成功,在查找表中的位置是" + result);elseSystem.out.println("查找" + key + "失败");key = 80;result = searchSeq(st, key);if(result > 0)System.out.println("查找" + key + "成功,在查找表中的位置是" + result);elseSystem.out.println("查找" + key + "失败");}}
运行结果:

算法分析

查找成功时的平均查找次数为:
      ASL=(1+2+3+4+……+n)/n = (n+1)/2   ①
查找不成功时的比较次数为:
      ASL=(n(n+1))/n = n+1               ②
则顺序查找的平均查找长度为:
      ASL==(① + ②)/2 = 3(n+1)/4
优点:算法简单,无需排序,采用顺序和链式存储均可。
缺点:平均查找长度较大。

1.2折半查找(有序表的查找)

查找思想:先确定待查找记录所在的范围,然后逐步缩小范围,直到找到或确认找不到该记录为止。
前提条件:必须在具有顺序存储结构有序表中进行。

示例:假设给定有序表中10个关键字为8,17,25,44,68,77,98,100,115,125,将查找K=17和K=120的情况

代码实现:

package search;public class StaticSearch {/** * @param args *///在有序表st中折半查找其关键字等于key的数据元素,若找到,则函数值为该元素在表中的位置,否则返回0public int searchBin(int[] st, int key){//st表的0号单元不使用int low = 1, high = st.length - 1, mid = (low + high)/2;while(low <= high){if(st[mid] == key)return mid;else if(st[mid] > key)high = mid - 1;else//st[mid] < keylow = mid + 1;}return 0;//low > high时表明查找失败}public static void main(String[] args) {// TODO Auto-generated method stub//有序表的二分查找测试int st[] = {0, 8, 17, 25, 44, 68, 77, 98, 100, 115, 125};//0号单元不使用int key = 17;int result = searchSeq(st, key);if(result > 0)System.out.println("查找" + key + "成功,在查找表中的位置是" + result);elseSystem.out.println("查找" + key + "失败");key = 120;result = searchSeq(st, key);if(result > 0)System.out.println("查找" + key + "成功,在查找表中的位置是" + result);elseSystem.out.println("查找" + key + "失败");}}
运行结果:

算法分析:

    为了分析二分查找的性能,可以用二叉树来描述二分查找过程。把当前查找区间的中点作为根结点,左子区间和右子区间分别作为根的左子树和右子树,左子区间和右子区间再按类似的方法,由此得到的二叉树称为二分查找的判定树
    例:关键字序列{8,17,25,34,48,57,68}的判定树


    由于第 k 层结点的查找次数各为 k 次(根结点为第1层),而第 k 层结点数最多为 2^k-1 个。假设该二叉树深度为 h,则等概率下,二分查找的成功的 ASL 为:


最坏情形下:① 取等号;② 最大的结点数n = 2^h -1;
则h=log2(n+1),因此 ,ASL=(n+1)/n log2(n+1)-1
当 n 很大时,ASL --> log2(n+1)-1 ,则其时间复杂度为O(log2n)。 
    二分查找的效率比顺序查找高,但只能适用于有序表,而排序本身是一种很费时的运算,即使采用高效率的排序方法也要花费O(nlog2n)的时间;另外,二分查找只适用于顺序存储结构(对线性表表示无法进行二分查找)

1.3索引顺序查找(分块查找)

    查找思想:是顺序查找的一种改进方法,就是把被查找的表分成若干块,每块中记录的存放顺序是无序的,但块与块之间必须按关键字有序。即第一块中任一记录的关键字都小于第二块中任一记录的关键字,而第二块中任一记录的关键字都小于第三块中任一记录的关键字,依此类推。
    该方法要为被查找的表建立一个索引表,索引表中的一项对应于表中的一块,索引表中含有这一块中的最大关键字和指向块内第一个记录位置的指针,索引表中各项关键字有序

查找步骤:
1)折半查找索引表(当然也可以顺序查找索引表,整体的查找速度也是比原始的顺序查找高的,但远不及折半查找),确定要找的记录所在块;
2)在相应的块中顺序查找。

示例:

代码实现:

package search;public class StaticSearch {/** * @param args */public static int searchIndex(int[][] index, int[] st, int key){//为方便,index[],st[]均使用0号单元//折半查找索引表int low = 0, high = index[0].length - 1;int block = index[0].length, elemsInBlock = st.length / block;int start, mid = 0;while(low < high){mid = (low + high)/2;if(index[0][mid] == key){start = mid;break;}else if(index[0][mid] > key)high = mid;else//index[0][mid] < keylow = mid + 1;}start = index[1][low];//从start位置开始顺序查找int i = 0;while(i < elemsInBlock && st[start+i] != key){i++;}if(i == elemsInBlock)return -1;elsereturn start+i;}public static void main(String[] args) {// TODO Auto-generated method stub//索引顺序查找,又叫分块查找,是顺序查找的一种改进方法,块间可使用折半查找,块内只能是顺序查找int[][] index = {{20, 53, 89},         {0, 5, 10}};//索引表int[] st = {18, 12, 8, 5, 20, 51, 36, 22, 29, 53, 89, 60, 72, 66, 76};//查找表int key = 22;int result = searchIndex(index, st, key);if(result > -1)System.out.println("查找" + key + "成功,在查找表中的位置是" + result);elseSystem.out.println("查找" + key + "失败");key = 6;result = searchIndex(index, st, key);if(result > -1)System.out.println("查找" + key + "成功,在查找表中的位置是" + result);elseSystem.out.println("查找" + key + "失败");}}



算法分析:

      设把长度为n的表分成均等的b个子表,每个子表有S个对象,则 b=n/s 。又设表中每个对象的查找概率相等,子表为1/b,子表内各对象为1/s 。
  则顺序查找确定块的成功ASL为:ASL1=(b+1)/2+(s+1)/2=(b+s)/2+1
  折半查找确定块的成功ASL为: ASL2=log2(b+1)-1+(s+1)/2=log2(1+n/s)+s/2
  可见,索引查找的ASL与表的长度n和子表内对象的个数s有关。

1 0
原创粉丝点击