几种查找的时间复杂度

本文详细介绍了几种常见的查找算法,包括顺序查找、二分查找、插值查找、斐波那契查找、树表查找、分块查找及哈希查找的时间复杂度。通过对比不同算法在最好、最坏及平均情况下的表现,帮助读者理解各种查找算法的效率特点。

1、顺序查找:
(1)最好情况:要查找的第一个就是。时间复杂度为:O(1)
(2)最坏情况:最后一个是要查找的元素。时间复杂度未:O(n)
(3)平均情况下就是:(n+1)/2。
所以总的来说时间复杂度为:O(n)
2、二分查找:O(log2n)->log以2为底n的对数
解释:2^t = n; t = log(2)n;
3、插值查找:O(log(2)(log(2)n))->log以2为底的(log以2为底的n的对数)的对数
4、斐波那契查找:O(log2n)->log以2为底n的对数
5、树表查找:
(1)二叉树:O(log2n)~O(n)之间
(2)红黑树:O(lgn)
(3)B和B+树:O(log2n)
6、分块查找:O(log2n)~O(n)之间
7、哈希查找:O(1)

<think> 题目要求不使用顺序查找(即线性查找)而使用时间复杂度更低的方法。由于题目中说明顺序表中无重复元素,且输入的元素不超过100个,但为了追求更低的查找时间复杂度,我们可以考虑使用二分查找(前提是有序)。但是题目没有说明顺序表是有序的,所以我们有两种选择: 1. 先对顺序表排序,然后使用二分查找。这样排序的时间复杂度为O(n log n),而每次查找时间复杂度为O(log n)。如果查找次数很多,这种方法更优。 2. 使用哈希表(例如unordered_map)来存储每个元素的位序,这样每次查找时间复杂度为O(1),但是需要额外的空间。 根据题目要求,输入的第一行是顺序表元素,且无重复。我们可以使用哈希表(散列表)来实现O(1)的查找。具体做法是: - 用一个数组存储顺序表的元素(按输入顺序) - 同时用一个unordered_map来映射元素值到其位置(位序) 但是注意:题目要求从1开始的位序。 步骤: a. 读入n b. 定义一个数组(可以不用,但为了通用性,我们保留顺序表存储) c. 定义一个unordered_map<int, int>,键为元素值,值为位序(即下标+1) d. 读入n个整数,同时存入数组(可以省略,只存map),并在map中记录每个元素的位序。 e. 然后读入待查找元素,直到-1结束。对于每个元素,在map中查找,如果找到则输出位序,否则输出0。 这样,查找操作的平均时间复杂度为O(1),最坏情况为O(n)(但通常不会发生,因为哈希表设计良好的话冲突很少)。 由于题目中元素不超过100个,所以哈希表不会很大,而且元素值不超过1000,所以完全可以用数组下标直接映射(即用空间换时间): - 因为元素值不超过1000,所以我们可以用一个大小为1001的数组(下标0到1000)来直接存储位序。这样查找就是O(1)。 具体代码实现: int *hashTable = new int[1001](); // 初始化全0 然后读入顺序表元素时,对于元素x,令hashTable[x] = i+1;(i是下标) 这样在查找时,直接根据元素值作为下标访问数组即可。 但是注意:题目中元素是正整数,且不超过1000,所以数组大小1001足够(包括0不用,下标1到1000)。 因此,我们使用一个大小为1001的数组作为哈希表,初始化为0。然后读入顺序表元素时,将元素值作为索引,将位序存入该位置。查找时,直接取该元素值对应的数组值,如果为0则说明不存在,否则就是位序。 这种方法比顺序查找快,尤其当查找次数多时。 但是注意:题目要求顺序查找,但这里要求不用顺序查找,所以采用此方法。 代码: 注意:题目要求最后以-1结束,且-1不需要查找。 例如输入样例: 9 3 7 9 1 4 6 2 5 8 3 8 2 9 10 -1 输出:1 9 7 3 0 代码实现: 由于题目要求每个数字后面跟一个空格,我们直接输出即可。 修改后的代码: ```cpp #include <iostream> using namespace std; int main() { int n; cin >> n; // 创建哈希表数组,大小为1001(因为元素值最大为1000),初始化为0 int hashTable[1001] = {0}; // 全部初始化为0 for (int i = 0; i < n; i++) { int num; cin >> num; // 将元素num的位序设为i+1 hashTable[num] = i + 1; } int target; while (cin >> target) { if (target == -1) { break; } // 如果target在哈希表中有记录(非0),则输出记录的值,否则输出0 if (target >= 1 && target <= 1000) { cout << hashTable[target] << " "; } else { // 如果target不在1到1000范围内,则一定不存在(因为顺序表元素都在1到1000) cout << "0 "; } } return 0; } ``` 注意:题目保证顺序表元素是正整数且不超过1000,所以当target在1到1000之间时,我们直接输出hashTable[target];如果target不在这个范围内(虽然题目输入待查找元素也是正整数,但为了安全,且题目说最后以-1结尾,所以当target为负数且不为-1时,我们不会进入循环,因为-1会break,但其他负数?题目说最后一行给出若干正整数,所以负数只有-1,所以我们在循环条件中读到-1会跳出,所以不会出现负数。但题目说待查找元素是正整数,所以我们可以不考虑负数。但是为了健壮性,我们检查了范围,如果不在1到1000之间,则直接输出0。 但是注意:题目中顺序表元素是正整数且不超过1000,所以如果待查找元素是0或者大于1000的数,那么肯定不存在,所以输出0。 因此,上述代码是安全的。 时间复杂度:初始化哈希表O(1)(固定1001),读入顺序表O(n),每次查找O(1),总的时间复杂度O(n+m)(m为查找次数)。 空间复杂度:O(1001) = O(1) 这种方法比顺序查找快得多,尤其是在多次查找的情况下。 §§相关问题§§: 1. 在什么情况下使用顺序查找比二分查找更合适? 2. 如果顺序表中有重复元素,如何修改哈希表方案以支持查找所有匹配的位置? 3. 哈希表查找时间复杂度是多少?最坏情况下的时间复杂度是多少? 4. 如果元素值的范围非常大(例如10^9),但元素个数n只有100,如何实现高效的查找? </think> ### 使用哈希表实现高效查找 (O(1)时间复杂度) ```cpp #include <iostream> using namespace std; int main() { const int MAX_VALUE = 1000; // 元素最大值 int hashTable[MAX_VALUE + 1] = {0}; // 哈希表数组 int n; cin >> n; // 建立哈希表:元素值→位置索引 for (int i = 1; i <= n; i++) { int num; cin >> num; hashTable[num] = i; // 存储元素位置(从1开始) } int target; while (cin >> target && target != -1) { // 读取直到-1 // 直接在哈希表中查找 if (target >= 1 && target <= MAX_VALUE && hashTable[target] != 0) { cout << hashTable[target] << " "; } else { cout << "0 "; } } return 0; } ``` ### 代码解释: 1. **哈希表设计**: - 创建大小为1001(元素最大值1000+1)的数组`hashTable` - 初始化所有元素为0(表示未存储) 2. **建立映射关系**: ```cpp for (int i = 1; i <= n; i++) { cin >> num; hashTable[num] = i; // 元素值作为索引,存储位置 } ``` - 将元素值直接作为数组索引 - 存储对应的位置序号(从1开始) 3. **O(1)时间复杂度查找**: ```cpp if (target >= 1 && target <= MAX_VALUE && hashTable[target] != 0) { cout << hashTable[target] << " "; } ``` - 直接通过元素值访问数组位置 - 非0值表示存在,值即为位置序号 - 0值表示不存在 ### 性能对比: | 查找方法 | 时间复杂度 | 空间复杂度 | 适用场景 | |---------|-----------|----------|---------| | 顺序查找 | O(n) | O(1) | 小规模无序数据 | | **哈希表查找** | **O(1)** | O(max_value) | 元素范围有限的无重复数据 | | 二分查找 | O(log n) | O(1) | 有序数据 | ### 为什么哈希表更快? - **直接寻址**:通过元素值直接计算存储位置 - **无比较操作**:省去了顺序查找中的循环比较 - **常数时间访问**:无论数据规模大小,访问时间恒定
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值