文章目录
- [【Unity/C# 基础算法】从入门到进阶:线性、插值与斐波那契查找深度解析](# 基础算法】从入门到进阶:线性、插值与斐波那契查找深度解析)
-
- [1. 线性查找 (Linear Search)](#1. 线性查找 (Linear Search))
-
- [1.1 原理](#1.1 原理)
- [1.2 优缺点](#1.2 优缺点)
- [1.3 C# 代码实现](# 代码实现)
- [2. 插值查找 (Interpolation Search)](#2. 插值查找 (Interpolation Search))
-
- [2.1 原理](#2.1 原理)
- [2.2 适用场景](#2.2 适用场景)
- [2.3 C# 代码实现](# 代码实现)
- [3. 斐波那契查找 (Fibonacci Search)](#3. 斐波那契查找 (Fibonacci Search))
-
- [3.1 原理](#3.1 原理)
- [3.2 算法逻辑](#3.2 算法逻辑)
- [3.3 C# 代码实现](# 代码实现)
- 总结与选择建议
【Unity/C# 基础算法】从入门到进阶:线性、插值与斐波那契查找深度解析
在 Unity 开发中,数据检索是性能优化的重头戏。无论是查找某个特定的 GameObject、管理背包道具,还是从大量的配置表中筛选数据,选择合适的查找算法都能显著提升运行效率。
本文将带你深入理解三种经典的查找算法:线性查找、插值查找以及斐波那契查找,并提供可以直接运行的 C# 代码示例。
1. 线性查找 (Linear Search)
1.1 原理
线性查找是最直观的算法。它不要求数据有序,而是从列表的首项开始,逐个比对,直到找到目标值或遍历完整个序列。
1.2 优缺点
优点:逻辑简单,对数据没有任何预处理要求。
缺点:当数据量很大时,平均搜索时间较长。
1.3 C# 代码实现
csharp
/// <summary>
/// 线性查找
/// </summary>
/// <param name="arr">数组</param>
/// <param name="target">目标值</param>
/// <returns>目标值的索引,未找到返回 -1</returns>
public static int LinearSearch(int[] arr, int target)
{
for (int i = 0; i < arr.Length; i++)
{
if (arr[i] == target)
return i;
}
return -1;
}
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( 1 ) O(1) O(1)
2. 插值查找 (Interpolation Search)
2.1 原理
插值查找是对 二分查找 (Binary Search) 的智能改进。二分查找总是从 1 / 2 1/2 1/2 处开始,而插值查找则会根据目标值的大小,动态预测它可能出现的位置。
其核心思想类似于我们在查字典时,找 "A" 开头的单词会从前面翻,找 "Z" 开头的会从后面翻。
计算位置的公式为:
p o s = l o w + ( t a r g e t − a r r [ l o w ] ) × ( h i g h − l o w ) a r r [ h i g h ] − a r r [ l o w ] pos = low + \frac{(target - arr[low]) \times (high - low)}{arr[high] - arr[low]} pos=low+arr[high]−arr[low](target−arr[low])×(high−low)
2.2 适用场景
数据必须是有序的。
数据分布较为均匀。如果分布极度不均(如数据突然跳跃很大),其性能可能不如二分查找。
2.3 C# 代码实现
csharp
public static int InterpolationSearch(int[] arr, int target)
{
int low = 0;
int high = arr.Length - 1;
// 确保目标值在数组范围内,避免计算出的 pos 越界
while (low <= high && target >= arr[low] && target <= arr[high])
{
if (low == high)
{
return arr[low] == target ? low : -1;
}
// 关键:自适应探测位置计算
int pos = low + (int)((double)(target - arr[low]) / (arr[high] - arr[low]) * (high - low));
if (arr[pos] == target)
return pos;
if (arr[pos] < target)
low = pos + 1;
else
high = pos - 1;
}
return -1;
}
时间复杂度: 平均 O ( log ( log n ) ) O(\log(\log n)) O(log(logn)),最坏 O ( n ) O(n) O(n)。
3. 斐波那契查找 (Fibonacci Search)
3.1 原理
斐波那契查找同样利用了有序数组的特性。它巧妙地利用 黄金分割原理。
它将数组长度扩展到某个斐波那契数 F [ k ] − 1 F[k]-1 F[k]−1,然后利用 F [ k − 1 ] F[k-1] F[k−1] 和 F [ k − 2 ] F[k-2] F[k−2] 将区间分为两部分。这种算法最大的特点是:它在循环中只使用 加减法,而不涉及除法或乘法,这在某些底层硬件或极致性能优化中具有优势。
3.2 算法逻辑
生成一个斐波那契数列。
找到大于等于数组长度的最小斐波那契数 F [ k ] F[k] F[k]。
将原数组拷贝并填充至 F [ k ] − 1 F[k]-1 F[k]−1 长度(通常用末尾元素填充)。
通过 i = o f f s e t + F [ k − 2 ] i = offset + F[k-2] i=offset+F[k−2] 进行分割查找。
3.3 C# 代码实现
csharp
public static int FibonacciSearch(int[] arr, int target)
{
int n = arr.Length;
int fib2 = 0; // F[k-2]
int fib1 = 1; // F[k-1]
int fibK = fib1 + fib2; // F[k]
// 1. 确定 F[k]
while (fibK < n)
{
fib2 = fib1;
fib1 = fibK;
fibK = fib1 + fib2;
}
int offset = -1;
while (fibK > 1)
{
// 确定分割点
int i = Math.Min(offset + fib2, n - 1);
if (arr[i] < target)
{
// 目标在右部,下移两级
fibK = fib1;
fib1 = fib2;
fib2 = fibK - fib1;
offset = i;
}
else if (arr[i] > target)
{
// 目标在左部,下移一级
fibK = fib2;
fib1 = fib1 - fib2;
fib2 = fibK - fib1;
}
else return i;
}
// 最后一个元素检查
if (fib1 == 1 && offset + 1 < n && arr[offset + 1] == target)
return offset + 1;
return -1;
}
时间复杂度: O ( log n ) O(\log n) O(logn)
优点: 核心运算仅需加减法,效率稳定且符合黄金比例分割。
总结与选择建议
| 算法 | 数据要求 | 平均复杂度 | 适用 Unity 场景 |
|---|---|---|---|
| 线性查找 | 无序 | O ( n ) O(n) O(n) | 简单的 UI 列表、小型动态数组 |
| 插值查找 | 有序且分布均匀 | O ( log ( log n ) ) O(\log(\log n)) O(log(logn)) | 大型静态数值配置表(如等级经验表) |
| 斐波那契查找 | 有序 | O ( log n ) O(\log n) O(logn) | 底层性能优化、避免除法开销的系统 |
博主寄语
如果你觉得这篇文章对你有帮助,欢迎点赞、收藏并关注!我是 [小郎君],我们下期见!