常用的查找算法有顺序查找,二分查找(折半查找),插值查找,斐波那契查找,下面我把每一种都举个例子。
1. 顺序查找(线性查找)
顺序查找是最简单的查找算法,它逐个比较数组中的元素,直到找到目标元素或遍历完数组。
cpp
#include <stdio.h>
// 顺序查找函数
int sequentialSearch(int arr[], int size, int target) {
for (int i = 0; i < size; i++) {
if (arr[i] == target) {
return i; // 找到目标,返回索引
}
}
return -1; // 未找到目标
}
int main() {
int arr[] = {12, 34, 54, 2, 3};
int size = sizeof(arr) / sizeof(arr[0]);
int target = 2;
int result = sequentialSearch(arr, size, target);
if (result != -1) {
printf("元素 %d 在索引 %d 处找到\n", target, result);
} else {
printf("元素 %d 未找到\n", target);
}
return 0;
}
2. 二分查找(折半查找)
二分查找要求数组是有序的,它通过不断将查找范围缩小一半来找到目标元素。
cpp
#include <stdio.h>
// 二分查找函数(递归实现)
int binarySearchRecursive(int arr[], int left, int right, int target) {
if (left <= right) {
int mid = left + (right - left) / 2; // 防止溢出
if (arr[mid] == target) {
return mid; // 找到目标,返回索引
} else if (arr[mid] < target) {
return binarySearchRecursive(arr, mid + 1, right, target); // 在右半部分查找
} else {
return binarySearchRecursive(arr, left, mid - 1, target); // 在左半部分查找
}
}
return -1; // 未找到目标
}
// 二分查找函数(迭代实现)
int binarySearchIterative(int arr[], int size, int target) {
int left = 0;
int right = size - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid; // 找到目标,返回索引
} else if (arr[mid] < target) {
left = mid + 1; // 在右半部分查找
} else {
right = mid - 1; // 在左半部分查找
}
}
return -1; // 未找到目标
}
int main() {
int arr[] = {2, 3, 12, 34, 54};
int size = sizeof(arr) / sizeof(arr[0]);
int target = 34;
int resultRecursive = binarySearchRecursive(arr, 0, size - 1, target);
int resultIterative = binarySearchIterative(arr, size, target);
if (resultRecursive != -1) {
printf("递归实现:元素 %d 在索引 %d 处找到\n", target, resultRecursive);
} else {
printf("递归实现:元素 %d 未找到\n", target);
}
if (resultIterative != -1) {
printf("迭代实现:元素 %d 在索引 %d 处找到\n", target, resultIterative);
} else {
printf("迭代实现:元素 %d 未找到\n", target);
}
return 0;
}
3. 插值查找
插值查找是二分查找的改进版本,它根据目标元素的位置动态调整查找点,适用于均匀分布的有序数组。
cpp
#include <stdio.h>
// 插值查找函数
int interpolationSearch(int arr[], int size, int target) {
int left = 0;
int right = size - 1;
while (left <= right && target >= arr[left] && target <= arr[right]) {
// 计算插值位置
int pos = left + ((target - arr[left]) * (right - left)) / (arr[right] - arr[left]);
if (arr[pos] == target) {
return pos; // 找到目标,返回索引
} else if (arr[pos] < target) {
left = pos + 1; // 在右半部分查找
} else {
right = pos - 1; // 在左半部分查找
}
}
return -1; // 未找到目标
}
int main() {
int arr[] = {10, 12, 13, 16, 18, 19, 20, 21, 22, 23, 24, 33, 35, 42, 47};
int size = sizeof(arr) / sizeof(arr[0]);
int target = 18;
int result = interpolationSearch(arr, size, target);
if (result != -1) {
printf("元素 %d 在索引 %d 处找到\n", target, result);
} else {
printf("元素 %d 未找到\n", target);
}
return 0;
}
4. 斐波那契查找
斐波那契查找利用斐波那契数列来确定查找点,适用于有序数组。
cpp
#include <stdio.h>
#include <stdlib.h>
// 生成斐波那契数列
void generateFibonacci(int fib[], int n) {
fib[0] = 0;
fib[1] = 1;
for (int i = 2; i < n; i++) {
fib[i] = fib[i - 1] + fib[i - 2];
}
}
// 斐波那契查找函数
int fibonacciSearch(int arr[], int size, int target) {
int fib[100]; // 存储斐波那契数列
generateFibonacci(fib, 100);
int fibM = 0; // 斐波那契数列的索引
// 找到大于等于数组长度的最小斐波那契数
while (fib[fibM] < size) {
fibM++;
}
// 创建临时数组,长度为 fib[fibM] - 1
int* temp = (int*)malloc((fib[fibM] - 1) * sizeof(int));
for (int i = 0; i < size; i++) {
temp[i] = arr[i];
}
for (int i = size; i < fib[fibM] - 1; i++) {
temp[i] = arr[size - 1];
}
int left = 0;
int right = size - 1;
while (left <= right) {
int mid = left + fib[fibM - 1] - 1;
if (temp[mid] == target) {
free(temp);
return (mid < size) ? mid : size - 1; // 找到目标,返回索引
} else if (temp[mid] < target) {
left = mid + 1;
fibM -= 2; // 继续在右半部分查找
} else {
right = mid - 1;
fibM -= 1; // 继续在左半部分查找
}
}
free(temp);
return -1; // 未找到目标
}
int main() {
int arr[] = {10, 22, 35, 40, 45, 50, 80, 82, 85, 90, 100};
int size = sizeof(arr) / sizeof(arr[0]);
int target = 85;
int result = fibonacciSearch(arr, size, target);
if (result != -1) {
printf("元素 %d 在索引 %d 处找到\n", target, result);
} else {
printf("元素 %d 未找到\n", target);
}
return 0;
}
算法特点总结
- 顺序查找
-
简单,适用于无序数组,时间复杂度为 (O(n)。
-
二分查找
-
效率高,适用于有序数组,时间复杂度为 O(log n))。
-
插值查找
-
在均匀分布的有序数组中性能优于二分查找,时间复杂度平均为 (O(log log n)),最坏为 (O(n)。
-
斐波那契查找
通过斐波那契数列确定查找点,避免了除法运算,适用于有序数组,时间复杂度为 (O(log n)。