查 找

导图

基本概念

查找: 在数据集合中寻找满足条件的数据元素的过程。结果分为查找成功和查找失败。

查找表: 用于查找的数据集合,由同一种数据类型(或记录)的组成,可以是一个数据或链表等数据类型。

操作: 分为静态查找表和动态查找表

  • 静态查找表:

    • 查询某个特定数据元素是否在表中。
    • 检索满足条件的某个特定的数据元素的各种属性。
  • 动态查找表:

    • 在查找表中插入一个数据元素。
    • 从表中删除一个数据元素。

关键字: 数据元素中唯一标识该元素的某个数据项的值,使用基于关键字的查找 ,查找的结果是唯一的。

平均查找长度: 关键字比较次数的平均值: ASL

顺序查找

顺序查找又称线性查找,主要用于在线性表中进行查找。

算法实现:

// 顺序存储
int Search(int arr[],int n, int key)
{
    int i;
    for(i=o; i<n; ++i)
    {
        if(arr[i] == key)
        {
            return i;
        }
    }
    return -1;
}


// 链式存储
LNode* Search(LNode* head, int key)
{
    LNode* p = head -> next;
    while(p != NULL)
    {
        if( p->data == key )
        {
            return p;
        }
        p = p->next;
    }
    return NULL;
}

注意:

ASL = n+12 (n为表中数据元素,查找失败则为n)

折半查找

折半查找又称二分查找

前提:对数据元素进行排序

思想:将待查找元素与中间元素比较,若大于中间元素(按升序排序),则在后半部分继续进行二分查找,以此类推直至找到元素,否则返回无此元素。

代码实现

// len 线性表长度, elem 查找关键字
int binSearch(int list[], int len, int elem)
{
    int left, right, mid;
    left = 0;
    right = len - 1;
    while( left <= right )
    {
        mid = (left + right)/2; //计算中间元素的下标
        if( list[mid] == elem )
        {
            return mid;
        }else if( list[mid] > elem )
        {
            //如果中间元素大于查找元素,则省略前半部分。
            left = mid + 1;
		}else if( list[mid] < elem )
        {
            //如果中间元素小于查找元素,则省略后半部分。
            right = mid - 1; 
        }
	}
    return -1;
}

注意:

  1. ASL = log2n

斐波那契查找

分块查找

分块查找又称索引顺序查找。分块查找需要对线性查找表进行分块并建立索引结构

思想:将线性查找表分块若干块,每块称为一个子表(子表无序,因此子表只能用顺序查找)。各表间满足分块有序,且后表各元素均大于前表

分块查找还需对分块的线性表,建立索引结构,包含关键字、子表长度和指针。

图示:

算法实现:

struct index    //定义块的结构
{
    int key;    //块的关键字
    int start;  //块的起始值
    int end;    //块的结束值
}index_table[4];    //定义结构体数组

int block_search(int key,int a[])  //自定义实现分块查找
{
    int i,j;
    i=1;
    while(i<=3&&key>index_table[i].key)  //确定在哪个块中
        i++;
    if(i>3)    //大于分得的块数,则返回0
        return 0;
    j=index_table[i].start;    //j等于块范围的起始值
    while(j<=index_table[i].end&&a[j]!=key)  //在确定的块内进行顺序查找
        j++;
    if(j>index_table[i].end)  //如果大于块范围的结束值,则说明没有要査找的数,j置0
        j = 0;
    return j;
}

int main()
{
    int i,j=0,k,key,a[16];
    printf("请输入15个数:\n");
    for(i=1;i<16;i++)
        scanf("%d",&a[i]);  //输入由小到大的15个数
    for(i=1;i<=3;i++)
    {
        index_table[i].start=j+1;  //确定每个块范围的起始值
        j=j+1;
        index_table[i].end=j+4;  //确定每个块范围的结束值
        j=j + 4;
        index_table[i].key=a[j];  //确定每个块范围中元素的最大值
    }
    printf("请输入你想査找的元素:\n");
    scanf("%d",&key);    //输入要查询的数值
    k=block_search(key,a);    //调用函数进行查找
    if(k!=0)
        printf("查找成功,其位置是:%d\n",k);  //如果找到该数,则输出其位置
    else
        printf("查找失败!");    //若未找到,则输出提示信息
    return 0;
}

注意:

  1. 子表是无序的,因此子表只能用顺序查找。
  2. 分块查找具有一定的有序性,即块与块之间有序。
  3. ASL = 12( m + nm) + 1 ( m为子表个数,n为查找表的长度)
  4. 分块查找的ASL既与线性查找表的长度有关,又与所分的子表数目有关。
  5. 当子表数目 m = n 时,ASL最小 ,即 n + 1

二叉排序树

性质:

  1. 若它的左子树不空,则左子树上所有关键字的值均小于其根关键字的值。
  2. 若它的右子树不空,则右子树上所有关键字的值均大于其根关键字的值。
  3. 左右子树又是一棵二叉排序树。

算法实现:

BTNOde* BSTSearch(BTNode* p, int key)
{
    //p首先指向根结点
    while( p != NULL)  
    {
        if( key == p->key) 
        {
            return p;
        }else if (key < p->key) 
        {
            // 如果查找值小于根结点则进入左子树查找
            p = p->lChild;
        }else{
            // 如果查找值大于根结点则进入右子树查找
            p = p->rChild;
        }        
    }
    return NULL; // 查找失败
}

平衡二叉树

B树

B+树

哈希查找

基本概念

哈希查找方法又称杂凑法、散列法。其中,选取的函数称为哈希函数,按照此方法建立的数据元素存储表称哈希表,哈希表中的存储单元的数量称为哈希表长

思想: 选取一个函数,用数据元素的关键字作为参数,计算该元素的存储地址,该存储位置称为哈希地址,并将数据元素存储在该位置。如果出现冲突,需要进行冲突处理。

哈希函数
  1. 直接定址法
  1. 以关键字的一个线性函数作为数据元素的存储地址。

  2. 该方法不会产生冲突,但当关键字跨度较大时会浪费内存

HASH(K) = a * k + b (a、b为常数)
  1. 除留取余法
  1. 以关键字除以M的余数作为数据元素的存储地址。

  2. M是一个常数,当M是一个素数或小于20的质数时,有利于减少冲突的发生。

HASH(k) = k % M
  1. 乘余取整法
HASH(K) = |b * (a * k - |a * k|)| (a、b为常数,且"0"<"a"<"1",b为整数)
  1. 折叠法

  2. 数字分析法

  3. 平方取中法

冲突处理

①:开放定址法

  • 线性探测法
( HASH(k) + d) % M

注意:

  1. M为哈希表长度, 1 <= i < M
  2. d = 1 ,2,3····,M-1
  • 二次探测法

    ②:链地址法

posted @   Gonfei  阅读(110)  评论(0编辑  收藏  举报
(评论功能已被禁用)
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示