数据结构复习1124查找

内容概述

顺序查找,分块查找,折半查找,B-树,B+-树,散列表,算法分析。

顺序查找:

  • 哨兵:不用判断表尾
  • AVL成功:((1+n)n/2)n=n/2;
  • AVL失败:1+n;
typedef struct
{
ElemType *data;
int len;
}SSnode;

int Serch_seq(ElemType e,SSnode* ST)
{
ST.data[0]=e;
for(i=ST.data[ST.len];i!=e;i--) ;
return i;
}

有序表顺序查找:

  • 优化了AVL失败
  • AVL失败=(1+2+...+n+n)/(n+1)=n/2+n/n+1;
typedef struct
{
ElemType *data;
int len;
}SSnode;

int Serch_seq(ElemType e,SSnode* ST)
{
ST.data[0]=e;
for(i=ST.data[ST.len];i!=e;i--) {if(e>ST.data[i]) return 0};
return i;
}

折半查找:

  • 仅适用于有序表
  • mid=left+right/2 ,向下取整。
int BinartSearch(SqList L,ElemType e)
{
int left=0,right=L.len-1,mid;
while(left<=right)
  {
    mid=(left+right)/2;
    if(SqList[mid]==e)return mid;
    if(SqList[mid]>e) right=mid-1;
    else{ left=mid+1 ;}
  }
return -1;
}
  • 循环条件left<=right。可以取等号。
  • ASL=Log(2,n+1)
  • 运算流程示例:


    image.png

分块查找:

  • 即索引顺序查找
  • 块间有序,块内无序。块间二分,块内顺序。
    代码:
  • 数据结构:块的左右边界,块内的最大元素值。
typedef strcut  IndexElem
{
int left,right,maxkey;
}IndexElem;
  • 查找
int BlockIndexSearch(ElemType key)
{ 
    int left=0,right=IndexTable.len-1;
    int mid=0;
    while(left<=right)
    {
        mid= (left+right)/2;
        if(IndexTable[mid]>key){right=mid-1;}
        if(IndexTable[mid]<key){right=mid+1;}
      }
  if((int i=IndexTable[right].right==Data.len-1)return -1;
  for(int i=IndexTable[left].left;i<=IndexTable[left].right;i++)
  {
      if(Data[i]==key)return i;
  }
  return -1;
}

B-树

概念
  • 平衡因子为0的多路平衡查找树;
  • m阶B树,每个结点最多有m-1个关键字,m个子树;最少有m/2.ceil个子树,m/2.ceil-1个关键字。
  • 树高为3,则叶节点均在4层。叶节点为null,代表查找失败。
  • log(m/2.ceil,n+1/2)+1=>h>=log(m,n+1)。
  • 左端:叶节点最少m/2.ceil,失败层最少有2(m/2.ceil)^(h-1)个结点。失败层的节点数=总关键字树+1。所以有n+1>=2(M/2.ceil)^(h-1)。即h-1<=log(m/2.ceil,n+1);
  • 令:根节点只有两个子树,其他节点至少有m/2.ceil。所以失败层(h+1)层最少节点数为2(m/2.ceil)^h-1;即第n层最少结点树为2(m/2.ceil)^(n-2);最多:m*(n-1),根节点最少1个关键字,最多m-1个。
基本操作:
  • 查找
  • 插入
  • 删除

B+-树

  • m阶B+树,每个结点做多m个关键字,m个子树;
  • 记录存储在叶节点
  • 分支结点仅包含下一级索引块的地址和最大值。

散列表:①散列构造,②冲突处理

概念:

  • 散列表是一种存储结构(不是顺序也不是随机),地址是关键字的一个函数;


    illustrate
  • 思维导图:
image.png
  • 装填因子:非null结点数/总长。装填因子越大,越容易产生冲突,查找效率越低。
  • 拉链法解决冲突:null指针的比较不计入比较次数,如3号链表长度为3,查找的key的H(key)为3,但链表中无key,则比较次数为3。

小专题:算法分析

哈希表的ASL:
  • 与表长无关,查找范围是[0,H(key)]若H(key)=key mod k,则范围为[0,k-1];

  • 计算思路:先找到每个结点的h(key),根据其和实际地址的差值计算每个结点的比较次数。


    image.png

    image.png
  • ASL成功=(16+2+33+4+9)/12= 2.5次

  • ASL失败=(1+(13+12+11+...+2))/13= 7次(注意分母是13)

空元素和空指针
  • 拉链法中,空指针不计入查找次数;
  • 线性探测中,空元素的比较计入查找次数。
顺序查找的ASL:
  • ASL成功=Σi/n=(n+1)/2
  • ASL失败=n+1(要查完所有元素直到空元素)
有序表
  • 对顺序查找ASL失败优化


    image.png
  • ASL成功=Σi/n=(n+1)/2 不变

  • ASL失败=(Σi+n)/(n+1)=n/2+n/(n+1)

折半查找
  • ASL成功<=h
  • ASL失败<=h(null指针不计入ASL)
  • h=log(2,n+1).ceiling
分块查找
  • n个节点被分成s块,每块b个。n=sb;

索引顺序查找(块内必顺序,索引可顺序可折半)

  • ASL成功 = (s+1)/2+(b+1)/2 = (s+1)/2+(n/s+1)/2 = (s^2+2s+n)/2s
  • ASL失败 = s+1+b+1

索引折半查找(块内必顺序,索引可顺序可折半)

  • ASL成功 <= log(2,s+1).ceil + (b+1)/2
  • ASL失败 <= log(2,s+1).ceil + (b+1)
时间复杂度
  • 顺序O(n)
  • 折半O(log(n))
  • 分块(O(n))
  • 哈希(O(1))

王道习题

1.折半查找的递归算法:

int BinarySearch(SqList L,ElemType key,int low,int high)
{
  int mid=(low+high)/2;
  if(low>high)return -1;
  if(L[mid]==key)return mid;
  return L[mid]>key? BinarySearch[L,key,low,mid-1]:BinarySearch[L,key,mid+1,high];
}

调用

result=BinarySearch(L,5,1,L.len)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容