【第六节】C/C++静态查找算法

news2024/11/19 9:31:59

目录

前言

一、搜索查找

二、查找算法

1. 线性查找(Linear Search)

2. 二分查找(Binary Search)

3. 插值查找(Interpolation Search)

4. 哈希查找(Hash Search)

5. Fibonacci查找


前言

        静态查找算法是在一个静态的数据结构(如数组或列表)中查找特定的元素。这些算法在执行查找操作时不会修改原始数据结构。以下是一些常见的静态查找算法:

顺序查找(Linear Search)
顺序查找是最简单的查找算法。它从数据结构的一端开始,逐个检查每个元素,直到找到所需的元素或到达数据结构的另一端。这种算法的时间复杂度为O(n),其中n是数据结构的长度。

二分查找(Binary Search)
二分查找是一种在有序数组中进行查找的高效算法。它首先将数组的中间元素与目标值进行比较,如果它们相等,则查找成功;如果目标值小于中间元素,则在数组的左半部分继续查找;如果目标值大于中间元素,则在数组的右半部分继续查找。这个过程递归地进行,直到找到目标值或搜索区间为空。二分查找的时间复杂度为O(log n)。

插值查找(Interpolation Search)
插值查找是对二分查找的一种改进,它根据元素的分布情况来调整搜索区间的大小,而不是每次都取中间元素。这种方法在数据分布均匀的情况下比二分查找更高效。

斐波那契查找(Fibonacci Search)
斐波那契查找也是基于二分查找的一种优化算法。它利用了斐波那契数列的性质来划分搜索区间。这种算法适用于均匀分布的数据集,其性能在某些情况下可能优于二分查找。

        在选择静态查找算法时,需要考虑数据的特点、规模以及查找的频繁程度。例如,如果数据是静态的且已经排好序,二分查找通常是最有效的选择。如果数据分布不均匀或数据量很大,插值查找或斐波那契查找可能更合适。然而,如果数据量较小或查找不频繁,顺序查找由于实现简单,可能也是一个可行的选择。

一、搜索查找

在数据集合之中,搜索具有特定关键字的结点通常可以根据不同的搜索场景和数据结构分为多种类型。

静态搜索表

  • 定义:当集合中的结点总数是固定的,或者变化非常少时,我们称之为静态搜索表。
  • 数据结构:静态搜索表可以是无序的,或者组织成有序表(如数组或有序链表)。
  • 搜索策略:对于无序的静态搜索表,通常使用线性搜索;对于有序的静态搜索表,则可以使用二分搜索或其他高效的搜索算法。

动态搜索表

  • 定义:当集合中的结点总数经常发生变化时,我们称之为动态搜索表。
  • 数据结构:动态搜索表通常组织成树形结构,如二叉搜索树(BST)、平衡二叉搜索树(如AVL树、红黑树)或B树/B+树等,以适应频繁的插入和删除操作。
  • 搜索策略:在树形结构中,搜索通常从根节点开始,根据关键字与节点值的比较结果决定向左子树还是右子树进行搜索,直到找到目标节点或确定不存在为止。

在内存中进行的搜索

  • 重点:由于内存访问速度相对较快,搜索的主要目标是减少比较或查找的次数,以提高搜索效率。
  • 评价标准:平均搜索长度(ASL),即从搜索开始到找到目标节点所需比较的平均次数。

在外存中进行的搜索

  • 重点:由于外存(如磁盘)的访问速度远慢于内存,搜索的主要目标是减少访问外存的次数,以降低I/O开销。
  • 数据结构:常用的数据结构包括索引文件、倒排索引等,它们通过特定的组织方式将数据与存储位置相关联,以便快速定位数据。
  • 评价标准:读盘次数,即从外存中读取数据的次数。由于每次读盘操作都涉及到I/O等待时间,因此减少读盘次数是优化外存搜索性能的关键。

二、查找算法

        静态搜索结果采用静态向量(或数组)。

        查找算法是计算机科学中一个基础且重要的主题,广泛应用于数据处理和信息检索。本文将介绍几种常见的查找算法,并使用C/C++语言展示它们的实现。

1. 线性查找(Linear Search)

        线性查找是最简单的查找算法,适用于未排序的数据集。它逐一检查数据集中的每个元素,直到找到目标值或遍历完所有元素。

#include <stdio.h>

int linearSearch(int arr[], int n, int x) {
    for (int i = 0; i < n; i++) {
        if (arr[i] == x) {
            return i; // 返回找到的元素的索引
        }
    }
    return -1; // 如果没有找到,返回-1
}

int main() {
    int arr[] = {2, 3, 4, 10, 40};
    int n = sizeof(arr) / sizeof(arr[0]);
    int x = 10;
    int result = linearSearch(arr, n, x);
    (result == -1) ? printf("元素不在数组中") : printf("元素在索引 %d", result);
    return 0;
}

2. 二分查找(Binary Search)

        二分查找是一种高效的查找算法,但要求数据集必须是有序的。它通过反复将查找范围减半来快速定位目标值。

#include <stdio.h>

// 二分查找算法
// arr[] 是一个升序排列的数组
// l 是要搜索的范围的左端点
// r 是要搜索的范围的右端点
// x 是要搜索的元素
int binarySearch(int arr[], int l, int r, int x) {
    while (l <= r) {
        // 防止 (l + r) 的和超过 int 的最大值
        int m = l + (r - l) / 2;

        // 检查中间元素
        if (arr[m] == x) {
            return m; // 元素找到,返回索引
        }

        // 如果中间元素小于x,忽略左半边
        if (arr[m] < x) {
            l = m + 1;
        } 
        // 如果中间元素大于x,忽略右半边
        else {
            r = m - 1;
        }
    }
    return -1; // 元素不在数组中,返回-1
}

int main() {
    int arr[] = {2, 3, 4, 10, 40}; // 输入数组
    int n = sizeof(arr) / sizeof(arr[0]); // 计算数组中的元素个数
    int x = 10; // 要查找的元素
    int result = binarySearch(arr, 0, n - 1, x); // 调用二分查找算法

    // 输出结果
    if (result == -1) {
        printf("元素不在数组中");
    } else {
        printf("元素在索引 %d", result);
    }
    
    return 0;
}

3. 插值查找(Interpolation Search)

        插值查找是二分查找的改进版本,适用于均匀分布的有序数据集。它通过估计目标值的位置来减少查找范围。

#include <stdio.h>

// 插值查找算法
// arr[] 是一个升序排列的数组
// n 是数组中元素的数量
// x 是要搜索的元素
int interpolationSearch(int arr[], int n, int x) {
    int lo = 0, hi = (n - 1);

    // 当待搜索的区段有效,并且目标值在[lo, hi]区间内时,执行搜索
    while (lo <= hi && x >= arr[lo] && x <= arr[hi]) {
        // 如果lo和hi相等,只需检查lo位置的元素
        if (lo == hi) {
            if (arr[lo] == x) return lo; // 找到目标值
            return -1; // 没有找到目标值
        }

        // 计算可能的位置pos,使用插值公式
        int pos = lo + (((double)(hi - lo) / (arr[hi] - arr[lo])) * (x - arr[lo]));

        // 如果找到了目标值,返回其索引
        if (arr[pos] == x) {
            return pos;
        }

        // 如果目标值大于pos位置的元素,调整lo
        if (arr[pos] < x) {
            lo = pos + 1;
        }
        // 如果目标值小于pos位置的元素,调整hi
        else {
            hi = pos - 1;
        }
    }
    return -1; // 如果没有找到目标值,返回-1
}

int main() {
    int arr[] = {2, 3, 4, 10, 40}; // 输入数组
    int n = sizeof(arr) / sizeof(arr[0]); // 计算数组中的元素个数
    int x = 10; // 要查找的元素
    int result = interpolationSearch(arr, n, x); // 调用插值查找算法

    // 输出查找结果
    if (result == -1) {
        printf("元素不在数组中");
    } else {
        printf("元素在索引 %d", result);
    }

    return 0;
}

4. 哈希查找(Hash Search)

        哈希查找利用哈希表来存储数据,通过计算键的哈希值来快速定位数据。哈希表的实现较为复杂,通常使用标准库中的哈希表数据结构。

#include <iostream>
#include <unordered_map>

int main() {
    // 创建一个unordered_map来存储数组元素和它们的索引
    std::unordered_map<int, int> hashMap;
    
    // 初始化数组
    int arr[] = {2, 3, 4, 10, 40};
    // 计算数组中的元素数量
    int n = sizeof(arr) / sizeof(arr[0]);
    
    // 将数组元素及其索引存入哈希表
    for (int i = 0; i < n; i++) {
        hashMap[arr[i]] = i;
    }
    
    // 要查找的元素
    int x = 10;
    
    // 在哈希表中查找元素
    auto it = hashMap.find(x);
    
    // 根据查找结果输出信息
    if (it != hashMap.end()) {
        // 如果元素在哈希表中,输出它的索引
        std::cout << "元素在索引 " << it->second << std::endl;
    } else {
        // 如果元素不在哈希表中,输出相应信息
        std::cout << "元素不在数组中" << std::endl;
    }
    
    return 0;
}

5. Fibonacci查找

        Fibonacci查找算法是一种基于Fibonacci数列的查找算法,它类似于二分查找,但使用Fibonacci数列来确定查找范围的分割点。这种算法适用于有序数组,并且可以在某些情况下比二分查找更高效。

#include <iostream>
#include <algorithm> // 用于std::min函数

// 斐波那契查找算法
// arr[] 是一个升序排列的数组
// n 是数组中元素的数量
// x 是要搜索的元素
int fibonacciSearch(int arr[], int n, int x) {
    // 初始化斐波那契数列
    int fibMMm2 = 0; // (m-2)'th 斐波那契数
    int fibMMm1 = 1; // (m-1)'th 斐波那契数
    int fibM = fibMMm2 + fibMMm1; // m'th 斐波那契数

    // 找到最小的斐波那契数,该数大于或等于n
    while (fibM < n) {
        fibMMm2 = fibMMm1;
        fibMMm1 = fibM;
        fibM = fibMMm2 + fibMMm1;
    }

    // 标记已经检查过的元素的偏移量
    int offset = -1;

    // 当还有斐波那契数剩余时,执行查找
    while (fibM > 1) {
        // 检查fibMMm2是否为有效位置
        int i = std::min(offset + fibMMm2, n - 1);

        // 如果x大于当前位置的元素,剪切数组的后半部分
        if (arr[i] < x) {
            fibM = fibMMm1;
            fibMMm1 = fibMMm2;
            fibMMm2 = fibM - fibMMm1;
            offset = i;
        }
        // 如果x小于当前位置的元素,剪切数组的前半部分
        else if (arr[i] > x) {
            fibM = fibMMm2;
            fibMMm1 -= fibMMm2;
            fibMMm2 = fibM - fibMMm1;
        }
        // 如果找到了x,返回索引
        else {
            return i;
        }
    }

    // 检查最后一个元素是否为x
    if (fibMMm1 && arr[offset + 1] == x) {
        return offset + 1;
    }

    // 如果未找到元素,返回-1
    return -1;
}

int main() {
    // 初始化数组
    int arr[] = {10, 22, 35, 40, 45, 50, 80, 82, 85, 90, 100};
    // 计算数组中的元素数量
    int n = sizeof(arr) / sizeof(arr[0]);
    // 要查找的元素
    int x = 85;
    
    // 调用斐波那契查找算法
    int result = fibonacciSearch(arr, n, x);
    
    // 输出查找结果
    if (result == -1) {
        std::cout << "Element not found" << std::endl;
    } else {
        std::cout << "Element found at index " << result << std::endl;
    }
    
    return 0;
}
  1. 初始化Fibonacci数列:首先,我们初始化Fibonacci数列的三个连续的Fibonacci数:fibMMm2(第(m-2)个Fibonacci数),fibMMm1(第(m-1)个Fibonacci数),和fibM(第m个Fibonacci数)。

  2. 找到最小的Fibonacci数:我们找到最小的Fibonacci数,该数大于或等于数组的长度n

  3. 缩小查找范围:使用Fibonacci数列来确定查找范围的分割点。如果目标值x大于当前元素,则向右移动Fibonacci数列;如果x小于当前元素,则向左移动Fibonacci数列。

  4. 检查最后一个元素:在循环结束后,检查最后一个元素是否为目标值。

  5. 返回结果:如果找到目标值,返回其索引;否则返回-1。

Fibonacci查找算法在某些情况下可以比二分查找更高效,尤其是在数组长度接近Fibonacci数时。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1882162.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

气膜足球馆需要投资多少—轻空间

随着足球运动的普及和人们对健康生活方式的追求&#xff0c;建设高质量的足球场地成为许多城市和社区的需求。在众多建设方案中&#xff0c;气膜足球馆因其独特的优势&#xff0c;逐渐成为一种受欢迎的选择。轻空间将探讨建设气膜足球馆所需的投资情况&#xff0c;并分析其成本…

InnoDB 表空间2---系统表空间

系统表空间 了解完了独立表空间的基本结构&#xff0c;系统表空间的结构也就好理解多了&#xff0c;系统表空间的结构和独立表空间基本类似&#xff0c;只不过由于整个MySQL进程只有一个系统表空间&#xff0c;在系统表空间中会额外记录一些有关整个系统信息的页&#xff0c;所…

MySQL之主从同步、分库分表

1、主从同步的原理 MySQL主从复制的核心是二进制日志 二进制日志&#xff08;binlog&#xff09;记录了所有DDL语句和DML语句&#xff0c;但不包括数据查询&#xff08;select、show&#xff09;语句。 1.1、复制分三步 master主库在事务提交时&#xff0c;会把数据变更记录…

干货分享:Spring中经常使用的工具类(提示开发效率)

环境&#xff1a;Spring5.3…30 1、资源工具类 ResourceUtils将资源位置解析为文件系统中的文件的实用方法。 读取classpath下文件 File file ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX "logback.xml") ; // ...读取文件系统文件 file Resou…

淘系-万相台无界实操运营课:淘系 付费工具课(40节课)

课程目录 01_万相台无界系统性忖费推广思维.mp4 02_万相台无界七大推广场景详解.mp4 03关键词推广计划之标准计划搭建技巧.mp4 04_关键词推广之智能计划推广技巧.mp4 05_关键词推广之趋势选品计划推广技巧.mp4 06关键词推广之智能选品计划推广技巧.mp4 07_非标品的关键词…

做好准备了吗?智能手机又一轮涨价潮来了……

还记得十一二年前&#xff0c;智能手机刚大力普及的时候&#xff0c;以小米、魅族为首的新势力品牌&#xff0c;快速打破三星、苹果及HTC们的高价门槛&#xff0c;将旗舰产品的价格快速压到了两千价位。‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ 一时间&#xff0c;手机市场快速完成了…

鸿蒙:路由Router原理

页面路由&#xff1a;在应用程序中实现不同页面之间的跳转和数据传递 典型应用&#xff1a;商品信息返回、订单等多页面跳转 页面栈最大容量为32个页面&#xff0c;当页面需要销毁可以使用router.clear()方法清空页面栈 router有两种页面跳转模式&#xff1a; router.pushUrl…

压缩算法LZ4

LZ4简介 LZ4 是无损压缩算法&#xff0c;提供每个核 大于 500 MB/s 的压缩速度&#xff0c;可通过多核 CPU 进行扩展。LZ4算法解压速度极快&#xff0c;单核解压速度达到GB/s&#xff0c;通常达到多核系统的 RAM 速度限制。 压缩速度可以动态调整&#xff0c;选择一个“加速”…

VLOOKUP函数在表格的简单运用-两个表匹配

1.什么是VLOOKUP&#xff1f; VLOOKUP是Excel中的一个内置函数&#xff0c;主要用于在区域或表格的首列查找指定的值&#xff0c;并返回该行中其他列的值。它特别适用于跨表格数据匹配 2.函数运用 2.1.这边两个表取名a表和b表&#xff0c;做为我们的实例表。 表格a包含&…

windows环境下创建python虚拟环境

windows环境下创建python虚拟环境 使用virtualenv库创建虚拟环境&#xff0c;可使不同的项目处于不同的环境中 安装方法&#xff1a; pip install virtualenv -i https://pypi.tuna.tsinghua.edu.cn/simple pip install virtualenvwrapper-win -i https://pypi.tuna.tsinghua…

git 还原被删除的分支

在多人项目开发中&#xff0c;有一次碰到忘记合并到master分支了&#xff0c;直接就把开发分支给删除了&#xff0c;现在记录下怎么还原被删除的分支 必须保证删除的分支之前已经被推送到了远程仓库 # 找出被删除分支的最后一个提交的哈希值 git reflog show# 找到提交哈希值…

【数据结构】(C语言):队列

队列&#xff1a; 线性的集合。先进先出&#xff08;FIFO&#xff0c;first in first out&#xff09;。两个指针&#xff1a;头指针&#xff08;指向第一个进入且第一个出去的元素&#xff09;&#xff0c;尾指针&#xff08;指向最后一个进入且最后一个出去的元素&#xff0…

虚拟机启动失败 请进行修复 关闭hyper-v

场景 win11开启夜神模拟器时弹出此提示。点击关闭hyper-v并重启电脑后仍然不行。 解决方法 关闭 Windows安全中心 的 内存完整性 后重启电脑恢复正常。 补充 由于我这里除了会用到夜神模拟器&#xff0c;还会用到docker&#xff0c;而docker又依赖hyper-v&#xff0c;不…

PHP基础教程——总结W3school

1、<?php ?> 2、$ 声明变量 3、变量大小写敏感 关键字&#xff08;if、else、echo&#xff09;和用户定义的类、函数大小写不敏感 4、三种注释 // # /* */ 5、echo "<br>"; 换行 6、global(关键字) 函数内访问全局变量 $GLOBALS[index] …

三坐标测量机的“柔性”特点及其在工业中的应用

现代制造业中&#xff0c;三坐标测量机&#xff08;CMM&#xff09;在产品开发、质量控制和生产过程中发挥着重要作用。它通过高精度准确测量工件的几何尺寸和形状&#xff0c;来保证产品质量符合严格的技术规范。CMM高精度和高效率的特点使其成为自动化生产线和质量控制流程中…

统一的可观察性和安全性如何增强你的业务?

作者&#xff1a;来自 Elastic Michael Calizo 利用人工智能、异常检测和增强攻击发现功能&#xff0c;在一个平台上增强组织的可观察性和安全性能力 当今数字环境中的组织越来越关注服务可用性&#xff0c;并保护其软件免受恶意篡改和攻击。传统的安全和可观察性工具通常以孤…

SpringMVC的架构有什么优势?——控制器(一)

文章目录 控制器(Controller)1. 控制器(Controller)&#xff1a;2. 请求映射(Request Mapping)&#xff1a;3. 参数绑定(Request Parameters Binding)&#xff1a;4. 视图解析器(View Resolver)&#xff1a;5. 数据绑定(Data Binding)&#xff1a;6. 表单验证(Form Validation)…

阿里云物联网应用层开发:第一部分,项目简介

文章目录 1、物联网应用层简介2、阿里云物联网应用层开发例程主要内容3、需要掌握基础知识 1、物联网应用层简介 应用层是物联网系统的用户界面&#xff0c;它提供了用户与系统交互的接口&#xff0c;这一层是将网络传输层的数据结果以易于理解和使用的方式呈现给用户&#xf…

企业互联网建站源码系统 附带完整的安装代码包以及搭建部署教程

系统概述 企业互联网建站源码吸系统是一款集众多先进功能于一身的建站工具。它提供了丰富的模板和组件&#xff0c;允许企业根据自身需求和品牌形象进行个性化定制&#xff0c;快速搭建出具有独特风格的网站。 代码示例 系统特色功能一览 1.用户友好界面&#xff1a;系统采用…

传感器的静态标定

1.传感器静态标定的基本概念 传感器的静态标定指标主要有线性度、灵敏度、重复性、灵敏度等。 &#xff08;1&#xff09;线性度 线性度是描述传感器静态特性的一个重要指标&#xff0c;以被测输入量处于稳定状态为前提。在规定条件下&#xff0c;传感器校准曲线与拟合直线间…