二分法的使用

关于二分法的详细使用

首先我第一次接触二分法是二分法的查找,

int BinaraySearch(int *array,int target,
                           unsigned int i,unsigned int n)
{

    int const j=i+n/2;
    if(n==1)
    {
            return i;
    }
    else
    {
    if(array[j]<=target)
        return BinaraySearch(array,target,j,n/2);
    else
        return BinaraySearch(array,target,i,n/2);
    }
}

这是一个相当简单的二分法的使用,无非就是给定一个已排序的数组,然后每次折中查找,直到找到相应的target值返回数组下标

接下来我接触到的对二分法的使用是使用二分法求解:

用二分法实现开根号求解:

 double u, d, k, n;
    scanf("%lf", &n);
    u = 10000000.0;
    d = 0;
    k=0;
    while( u - d > 0.000001)
    {
        printf("%lf %lf %lf %lf\n",u,d,k,k*k*k*k*k);
        k = (u + d) / 2;
        if ( k * k * k * k * k < n) d = k;
        else u = k;
    }

这段代码实现的功能也就是对n实现开5次根号,精度在0.000001之内,,,u表示的是二分的上限,d表示的二分下线,,,,,k值也就是二分值,不断根据k值的范围重新设定上限和下限,最终开出根号k值,

接下来是使用二分法进行排序:由于二分排序的平均时间是O(n2),所以本人也觉得吧!没什么用处的!

最后发一道POJ上的二分的题ID2456

Description

Farmer John has built a new long barn, with N (2 <= N <= 100,000) stalls. The stalls are located along a straight line at positions x1,...,xN (0 <= xi <= 1,000,000,000).

His C (2 <= C <= N) cows don't like this barn layout and become aggressive towards each other once put into a stall. To prevent the cows from hurting each other, FJ want to assign the cows to the stalls, such that the minimum distance between any two of them is as large as possible.  What is the largest minimum distance?

Input

* Line 1: Two space-separated integers: N and C

* Lines 2..N+1: Line i+1 contains an integer stall location, xi

Output

* Line 1: One integer: the largest minimum distance

Sample Input

5 3
1
2
8
4
9
<think>好的,现在我要处理用户的问题,关于在C++中使用数组实现类似map的功能,但这次不使用二分法。用户之前已经询问过使用二分法的情况,现在可能想了解替代方法或者比较不同方法的优缺点。 首先,我需要回忆一下之前给出的回答,用户已经知道如何用有序数组和二分法来实现高效的查找。现在如果不用二分法,可能的替代方案有哪些呢?常见的有线性查找、哈希表、或者二叉搜索树等结构,但用户明确提到使用数组,所以可能需要用数组结合其他查找方式。 用户的问题是不使用二分法,所以重点应该放在线性查找上,因为二分法需要数组有序,而线性查找则不需要,或者可以有不同的数据组织方式。比如,是否保持数组有序?如果使用无序数组,查找的时候需要线性扫描,但插入会更快,因为不需要移动元素。或者是否使用其他结构,比如链表,但用户指定的是数组,所以链表可能不在考虑范围内。 接下来,我需要考虑如何用数组实现类似map的功能,但查找不使用二分法。可能的思路有两种:保持数组无序,插入时直接追加,查找时线性扫描;或者使用其他数据结构如哈希表,但哈希表通常需要数组加链表(开链法)或者开放寻址法,但用户可能想要更简单的实现,不使用内置的哈希函数或者处理冲突的机制。 由于用户之前提到了用数组模拟map,可能希望保持简单,所以这里可能采用无序数组,插入快但查找慢。但这样效率会比较低,特别是当元素数量大时,查找的时间复杂度是O(n),而插入是O(1),但如果有重复键需要处理的话,插入可能也需要查找,导致O(n)的时间。 或者,是否可以使用其他方式组织数据,比如维护多个数组,或者使用某种分块策略来加速查找?但这样可能复杂度增加,用户可能希望一个简单的实现。 因此,最直接的替代方案是使用无序数组,每次插入时不排序,直接添加到末尾,查找时线性遍历。但这样增删查改的时间复杂度都会比较高。可能用户想知道这样的实现方式,或者是否有其他方法。 接下来,我需要组织回答的结构,按照之前的模板:数据结构设计,核心操作实现,时间复杂度分析,优缺点对比,改进方向等。需要指出,不使用二分法的情况下,查找效率会下降,但插入可能更快(如果不需要维护有序的话)。 另外,需要比较两种方法:使用有序数组(二分查找)和无序数组(线性查找)的优缺点。用户可能想知道在不同场景下哪种更合适,或者为什么有时候不用二分法,比如数据量小的时候,线性查找可能更简单,或者插入频繁但查找次数少的情况。 此外,可能需要提到其他可能性,比如如果允许重复键,或者需要其他操作,但用户的问题可能更关注基本的增删查改。 最后,需要确保代码示例正确,不使用二分查找,比如在findIndex函数中使用循环遍历,而不是二分法。同时,注意插入时是否需要检查重复键,并在存在时更新,否则追加到数组末尾。删除时需要找到元素并移动后续元素,时间复杂度O(n)。 总结步骤: 1. 数据结构设计:无序数组,Entry结构体,记录键对,动态数组或固定大小。 2. 查找操作:线性遍历数组,直到找到匹配的键。 3. 插入操作:先查找是否存在,存在则更新,否则追加到末尾(可能需要处理数组满的情况)。 4. 删除操作:找到元素后,移动后续元素前移。 5. 修改操作:查找后直接修改。 6. 访问操作:类似之前的operator[],查找或插入默认。 7. 时间复杂度分析:查找O(n),插入O(n)(因为需要先查找是否存在),删除O(n),修改O(n)。 8. 优缺点:实现简单,适合小数据量;但效率低,不适合大数据量。 9. 改进方向:如使用哈希表、保持有序但用其他查找方法等。 在代码实现时,需要注意处理数组满的情况,可能需要动态扩容(比如使用vector),但用户的问题可能假设使用固定数组,所以需要断言或者错误处理。 现在需要把这些思路整理成结构化的回答,使用中文,符合之前的格式,但针对不使用二分法的情况。</think>--- ### 一、数据结构设计(无序数组方案) ```cpp template <typename Key, typename Value, int MAX_SIZE = 1000> class ArrayMap { private: struct Entry { Key key; Value value; }; Entry entries[MAX_SIZE]; // 无序数组 int size = 0; // 当前元素数量 }; ``` --- ### 二、核心操作实现 #### 1. **查找操作(线性扫描)** ```cpp // 返回键对应的下标,未找到返回-1 int findIndex(const Key& key) const { for (int i = 0; i < size; ++i) { if (entries[i].key == key) { return i; } } return -1; } ``` #### 2. **插入/修改操作** ```cpp void insert(const Key& key, const Value& value) { int index = findIndex(key); // 键已存在:直接修改 if (index != -1) { entries[index].value = value; return; } // 数组已满:需扩容或报错(此处简化为断言) assert(size < MAX_SIZE); // 无序插入:直接追加到末尾 entries[size++] = {key, value}; } ``` #### 3. **删除操作** ```cpp bool erase(const Key& key) { int index = findIndex(key); if (index == -1) return false; // 将最后一个元素覆盖到删除位置 entries[index] = entries[size-1]; size--; return true; } ``` #### 4. **访问操作** ```cpp Value& operator[](const Key& key) { int index = findIndex(key); if (index != -1) { return entries[index].value; } // 未找到则插入默认 insert(key, Value{}); return entries[size-1].value; // 新插入元素在末尾 } ``` --- ### 三、时间复杂度分析 | 操作 | 时间复杂度 | 说明 | |--------|------------|------------------------| | 查找 | O(n) | 线性遍历所有元素 | | 插入 | O(n) | 需先检查键是否已存在 | | 删除 | O(n) | 查找+覆盖 | | 修改 | O(n) | 查找+直接修改 | --- ### 四、方案特点 #### **优势**: 1. **实现简单**:无需维护数组有序性 2. **快速插入**:无需元素移动(直接追加到末尾) 3. **删除优化**:通过末尾元素覆盖删除位置,避免大规模数据移动 #### **劣势**: 1. **查找效率低**:必须遍历所有元素 2. **数据冗余风险**:可能存储重复键(需在插入时显式检查) --- ### 五、适用场景对比 | 方案 | 典型场景 | |--------------|-----------------------------------| | **有序数组** | 查找频繁,数据需要有序遍历 | | **无序数组** | 插入/删除频繁,数据量小(<100) | --- ### 六、改进方向 1. **哈希表优化** 使用简易哈希函数(如取模)定位桶位置: ```cpp int bucket_index = hash(key) % BUCKET_SIZE; ``` 配合链表处理冲突(类似`std::unordered_map`) 2. **分块查找** 将数组划分为多个块,记录每块的键范围,缩小查找范围 3. **缓存最近访问** 添加`last_accessed_index`字段,优先检查最近访问的元素 --- ### 七、代码示例(哈希表优化版) ```cpp // 简易哈希表实现(开链法) template <typename Key, typename Value, int BUCKET_SIZE = 100> class SimpleHashMap { private: struct Entry { Key key; Value value; Entry* next = nullptr; }; Entry* buckets[BUCKET_SIZE] = {nullptr}; int hash(const Key& key) const { return std::hash<Key>{}(key) % BUCKET_SIZE; } }; ``` --- ### 总结 不使用二分法时,**无序数组方案**更适合数据量小或插入操作密集的场景。若需提升性能,可结合哈希表思想,但完整实现哈希表需处理冲突、扩容等复杂问题。实际开发中仍推荐优先使用STL容器。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值