极速查找(1)-算法分析

简介: 极速查找(1)-算法分析

查找概论

查找表是由同一类型的数据元素(或记录)构成的集合
查找算法是计算机科学中重要的概念之一,它是指在给定的数据集合中查找目标
元素。查找算法的目标是在最少的比较次数或操作下,快速确定目标元素的存在
或位置。

查找分类

查找表按照操作方式来分两大种。

一种是静态查找表,只做查找操作的查找表。
  主要操作有,查询某个特定的数据元素是否在查找表中。检索某个特定的数
  据元素和各种属性。
一种是动态查找表,在查找过程中同时插入查找表中不存在的数据元素,或者从
查找表中删除已经存在的某个数据元素。
  主要操作有,查找时插入数据元素,查找十删除数据元素。

顺序表查找

顺序查找 (Sequential Search),也被称为线性查找,是一种简单直观的查找
算法。顺序查找是从数据集合的起始位置开始逐个与目标元素进行比较,直到找
到目标元素或遍历完整个数据集合。

顺序查找算法实现

public class SequentialSearch {
    public static int search(int[] arr, int target) {
        // 遍历数组中的每个元素
        for (int i = 0; i < arr.length; i++) {
            // 如果找到目标元素,返回其索引
            if (arr[i] == target) {
                return i;
            }
        }
        // 若遍历完整个数组都没有找到目标元素,则返回-1表示未找到
        return -1;
    }
    public static void main(String[] args) {
        int[] arr = {5, 3, 9, 2, 7, 1};
        int target = 7;
        int result = search(arr, target);
        if (result == -1) {
            System.out.println("目标元素未找到");
        } else {
            System.out.println("目标元素在索引" + result + "处");
        }
    }
}
运行代码,输出结果为:“目标元素在索引4处”,表示目标元素7在数组的索引4
处。若将target修改为10,运行结果将为:“目标元素未找到”。
public class SequentialSearch {
    public static int search(int[] arr, int target) {
        int n = arr.length;
        // 遍历数组中的每个元素
        for (int i = 0; i < n; i++) {
            // 判断当前元素是否等于目标元素
            if (arr[i] == target) {
                // 将目标元素与当前元素交换,以提高下次查找时的性能
                if (i > 0) {
                    int temp = arr[i];
                    arr[i] = arr[i - 1];
                    arr[i - 1] = temp;
                }
                return i - 1; // 返回当前元素的索引
            }
        }
        return -1; // 未找到目标元素
    }
    public static void main(String[] args) {
        int[] arr = {5, 3, 9, 2, 7, 1};
        int target = 7;
        int result = search(arr, target);
        if (result == -1) {
            System.out.println("目标元素未找到");
        } else {
            System.out.println("目标元素在索引" + result + "处");
        }
    }
}
在上述代码中,我们进行了以下优化:
  将目标元素与它之前的元素交换位置。通过这种交换,我们可以确保下次查
  找时,目标元素就在前面,减少了遍历的次数。这种优化思路适用于在查找
  过程中频繁查询相同的元素,希望将这些元素移动到开头以提高下次查询的
  效率。
注意
  在交换元素位置时,我们需要确保当前元素的索引大于0,以避免越界。返
  回值也相应地从i改为i - 1,以反映元素交换后的位置。
但是,如果数据集合较大,并且存在大量重复查询的情况,可能会更适合使用其
他更高效的查找算法。

有序表查找

折半查找(二分查找)

折半查找(Binary Search),也被称为二分查找,是一种高效的查找算法。它
适用于已经排序的数据集合,通过将目标元素与数据集合的中间元素进行比较,
可以迅速缩小查找范围。这个过程类似于猜数字游戏中每次猜测的策略,不断地
将搜索范围缩小一半。

分析

折半查找的时间复杂度为O(log n),其中n是数据集合中的元素个数。因为在每
次比较后,查找范围都缩小一半,因此查找所需的比较次数随着数据集合的增长
而以对数方式增加。

注意

折半查找要求数据集合已经按升序或降序排序,以确保查找的正确性。如果数据
集合未排序,需要先进行排序操作,然后才能使用折半查找来定位目标元素的位
置。

代码实现

public class BinarySearch {
    public static int search(int[] arr, int target) {
        int low = 0;
        int high = arr.length - 1;
        while (low <= high) {
            int mid = low + (high - low) / 2;
            if (arr[mid] == target) {
                return mid; // 找到目标元素,返回索引
            } else if (arr[mid] < target) {
                low = mid + 1; // 目标元素在右侧,更新查找范围为右半部分
            } else {
                high = mid - 1; // 目标元素在左侧,更新查找范围为左半部分
            }
        }
        return -1; // 目标元素未找到
    }
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 5, 7, 9};
        int target = 7;
        int result = search(arr, target);
        if (result == -1) {
            System.out.println("目标元素未找到");
        } else {
            System.out.println("目标元素在索引" + result + "处");
        }
    }
}

插值查找

插值查找(Interpolation Search)是一种改进的查找算法,它在数据集合中
进行查找时,根据目标元素与数据集合中最小值和最大值的相对位置,进行更精
细的插值估计,从而快速缩小查找范围。

步骤

1、确定查找范围的起始点和终点,通常为数组的首尾两个索引。
2、计算目标元素的估计位置:
  (1)假设数据集合的最小值为min,最大值为max。
  (2)计算目标元素在数据集合中的相对位置:(target - arr[start]) / 
  (arr[end] - arr[start]),其中target为目标元素的值。
  (3)使用上述相对位置乘以查找范围的长度,得到目标元素的估计位置。
  (4)转换为整数索引,得到划分点。
3、将目标元素与划分点处的元素进行比较:
  (1)若目标元素等于划分点处的元素,查找成功,返回划分点的索引。
  (2)若目标元素小于划分点处的元素,说明目标元素在划分点的左侧,更
  新终点为划分点的前一个位置。
  (3)若目标元素大于划分点处的元素,说明目标元素在划分点的右侧,更
  新起始点为划分点的后一个位置。
4、重复步骤2和步骤3,直到找到目标元素或起始点大于终点,表示目标元素不
  存在。

分析

插值查找的时间复杂度在平均情况下为O(log log n),但最坏情况下可能达到
O(n),其中n是数据集合中的元素个数。插值查找适合于数据集合中分布较为均
匀的情况,对于分布不均或有序性较差的数据集合,插值查找的效果可能变差。

注意

插值查找也要求数据集合已经按升序或降序排序。如果数据集合未排序,需要先
进行排序操作,然后才能使用插值查找来定位目标元素的位置。

代码实现

public class InterpolationSearch {
    public static int search(int[] arr, int target) {
        int low = 0;
        int high = arr.length - 1;
        while (low <= high && target >= arr[low] && target <= arr[high]) {
            int pos = low + (((high - low) * (target - arr[low])) / (arr[high] - arr[low]));
            if (arr[pos] == target) {
                return pos; // 找到目标元素,返回索引
            } else if (arr[pos] < target) {
                low = pos + 1; // 目标元素在右侧,更新查找范围为右半部分
            } else {
                high = pos - 1; // 目标元素在左侧,更新查找范围为左半部分
            }
        }
        return -1; // 目标元素未找到
    }
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 5, 7, 9};
        int target = 7;
        int result = search(arr, target);
        if (result == -1) {
            System.out.println("目标元素未找到");
        } else {
            System.out.println("目标元素在索引" + result + "处");
        }
    }
}

斐波那契查找

斐波那契查找(Fibonacci Search)是一种基于斐波那契数列的查找
算法。它结合了二分查找和插值查找的优点,可以在特定条件下提供更
好的性能。

步骤

1、确定斐波那契数列的长度,使得最小的斐波那契数不小于待查找数
据集合的长度。即找到最小的斐波那契数F[k],满足F[k] >= n。
2、将数据集合扩展到长度为F[k],扩展部分使用数据集合最后一个元
素填充。
3、定义两个指针,low和high,初始值分别为0和F[k] - 1。
4、将待查找元素与指针low和high对应的元素进行比较。
  (1)若待查找元素等于指针low对应的元素,表示找到了目标元
  素,返回low。
  (2)若待查找元素大于指针low对应的元素,说明目标元素在右
  侧,指针low右移到指针high的位置,指针high右移两位。
  (3)若待查找元素小于指针low对应的元素,说明目标元素在左
  侧,指针low左移两位,指针high左移一位。
5、重复步骤4,直到找到目标元素,或者指针low大于指针high,表
示目标元素不存在。

注意

斐波那契查找的前提条件是数据集合必须是有序的。与二分查找不同,
斐波那契查找不是将查找范围划分为两部分,而是通过斐波那契数列的
特性来确定待查找元素的位置。

代码实现

public class FibonacciSearch {
    public static int search(int[] arr, int target) {
        int len = arr.length;
        int fib2 = 0; // F[k-2]
        int fib1 = 1; // F[k-1]
        int fibK = fib2 + fib1; // F[k]
        while (fibK < len) {
            fib2 = fib1;
            fib1 = fibK;
            fibK = fib2 + fib1;
        }
        int offset = -1; // 偏移量
        int low = 0;
        while (fibK > 1) {
            int index = Math.min(offset + fib2, len - 1);
            if (arr[index] < target) {
                fibK = fib1;
                fib1 = fib2;
                fib2 = fibK - fib1;
                offset = index;
                low = index + 1;
            } else if (arr[index] > target) {
                fibK = fib2;
                fib1 = fib1 - fib2;
                fib2 = fibK - fib1;
            } else {
                return index; // 找到目标元素,返回索引
            }
        }
        if (fib1 == 1 && arr[low] == target) {
            return low; // 找到目标元素,返回索引
        }
        return -1; // 目标元素未找到
    }
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 5, 7, 9};
        int target = 7;
        int result = search(arr, target);
        if (result == -1) {
            System.out.println("目标元素未找到");
        } else {
            System.out.println("目标元素在索引" + result + "处");
        }
    }
}
相关文章
|
3月前
|
机器学习/深度学习 算法 搜索推荐
从理论到实践,Python算法复杂度分析一站式教程,助你轻松驾驭大数据挑战!
【10月更文挑战第4天】在大数据时代,算法效率至关重要。本文从理论入手,介绍时间复杂度和空间复杂度两个核心概念,并通过冒泡排序和快速排序的Python实现详细分析其复杂度。冒泡排序的时间复杂度为O(n^2),空间复杂度为O(1);快速排序平均时间复杂度为O(n log n),空间复杂度为O(log n)。文章还介绍了算法选择、分而治之及空间换时间等优化策略,帮助你在大数据挑战中游刃有余。
97 3
|
5月前
|
人工智能 算法 BI
第一周算法设计与分析 D : 两面包夹芝士
这篇文章介绍了解决算法问题"两面包夹芝士"的方法,通过找出两个数组中的最大最小值,计算这两个值之间的整数个数,包括特判不存在整数的情况。
|
6天前
|
存储 算法 安全
基于哈希表的文件共享平台 C++ 算法实现与分析
在数字化时代,文件共享平台不可或缺。本文探讨哈希表在文件共享中的应用,包括原理、优势及C++实现。哈希表通过键值对快速访问文件元数据(如文件名、大小、位置等),查找时间复杂度为O(1),显著提升查找速度和用户体验。代码示例展示了文件上传和搜索功能,实际应用中需解决哈希冲突、动态扩容和线程安全等问题,以优化性能。
|
15天前
|
缓存 算法 搜索推荐
Java中的算法优化与复杂度分析
在Java开发中,理解和优化算法的时间复杂度和空间复杂度是提升程序性能的关键。通过合理选择数据结构、避免重复计算、应用分治法等策略,可以显著提高算法效率。在实际开发中,应该根据具体需求和场景,选择合适的优化方法,从而编写出高效、可靠的代码。
27 6
|
2月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
70 1
|
3月前
|
并行计算 算法 IDE
【灵码助力Cuda算法分析】分析共享内存的矩阵乘法优化
本文介绍了如何利用通义灵码在Visual Studio 2022中对基于CUDA的共享内存矩阵乘法优化代码进行深入分析。文章从整体程序结构入手,逐步深入到线程调度、矩阵分块、循环展开等关键细节,最后通过带入具体值的方式进一步解析复杂循环逻辑,展示了通义灵码在辅助理解和优化CUDA编程中的强大功能。
|
3月前
|
算法
PID算法原理分析
【10月更文挑战第12天】PID控制方法从提出至今已有百余年历史,其由于结构简单、易于实现、鲁棒性好、可靠性高等特点,在机电、冶金、机械、化工等行业中应用广泛。
|
4月前
|
算法 搜索推荐 开发者
别再让复杂度拖你后腿!Python 算法设计与分析实战,教你如何精准评估与优化!
在 Python 编程中,算法的性能至关重要。本文将带您深入了解算法复杂度的概念,包括时间复杂度和空间复杂度。通过具体的例子,如冒泡排序算法 (`O(n^2)` 时间复杂度,`O(1)` 空间复杂度),我们将展示如何评估算法的性能。同时,我们还会介绍如何优化算法,例如使用 Python 的内置函数 `max` 来提高查找最大值的效率,或利用哈希表将查找时间从 `O(n)` 降至 `O(1)`。此外,还将介绍使用 `timeit` 模块等工具来评估算法性能的方法。通过不断实践,您将能更高效地优化 Python 程序。
76 4
|
4月前
|
算法 程序员 Python
程序员必看!Python复杂度分析全攻略,让你的算法设计既快又省内存!
在编程领域,Python以简洁的语法和强大的库支持成为众多程序员的首选语言。然而,性能优化仍是挑战。本文将带你深入了解Python算法的复杂度分析,从时间与空间复杂度入手,分享四大最佳实践:选择合适算法、优化实现、利用Python特性减少空间消耗及定期评估调整,助你写出高效且节省内存的代码,轻松应对各种编程挑战。
82 1
|
4月前
|
算法 数据可视化
基于SSA奇异谱分析算法的时间序列趋势线提取matlab仿真
奇异谱分析(SSA)是一种基于奇异值分解(SVD)和轨迹矩阵的非线性、非参数时间序列分析方法,适用于提取趋势、周期性和噪声成分。本项目使用MATLAB 2022a版本实现从强干扰序列中提取趋势线,并通过可视化展示了原时间序列与提取的趋势分量。代码实现了滑动窗口下的奇异值分解和分组重构,适用于非线性和非平稳时间序列分析。此方法在气候变化、金融市场和生物医学信号处理等领域有广泛应用。
244 19

热门文章

最新文章

下一篇
开通oss服务