技术问询:如何用首中尾元素中位数正确分区及多路归并函数排错
1. 如何使用首元素、中间元素和尾元素的中位数正确进行分区?
这个方法的核心是避免分区基准选得太极端(比如数组有序时选首/尾元素,导致分区极度不平衡),具体可以按以下步骤来实现:
- 第一步:计算中间索引。为了避免整数溢出,别直接用
(first+last)/2,而是用mid = first + (last - first)/2。 - 第二步:选出三个元素的中位数。通过三次比较交换,把最小的元素放到
first位置,最大的放到mid位置,中位数自然就落到last位置(或者你也可以把中位数换到first,后续逻辑对应调整就行)。 - 第三步:用常规的分区算法(比如Lomuto或Hoare分区法)完成分区,此时基准值就是我们选好的中位数。
给你写个可直接用的实现示例:
// 辅助函数:把三个元素的中位数放到last位置 int medianOfThree(vector<int>& list, int first, int last) { int mid = first + (last - first) / 2; // 三次比较交换,确保list[last]是中位数 if (list[first] > list[mid]) swap(list[first], list[mid]); if (list[first] > list[last]) swap(list[first], list[last]); if (list[mid] > list[last]) swap(list[mid], list[last]); return last; } int partition(vector<int>& list, int first, int last) { // 先获取中位数的位置,把它放到last作为基准 int pivotIdx = medianOfThree(list, first, last); int pivot = list[pivotIdx]; swap(list[pivotIdx], list[last]); // 确保基准在last // Lomuto分区逻辑 int i = first - 1; for (int j = first; j < last; j++) { if (list[j] <= pivot) { i++; swap(list[i], list[j]); } } // 把基准移到最终的正确位置 swap(list[i+1], list[last]); return i+1; }
2. 排查multiway_merge函数的问题
你的思路完全没问题——用最小堆维护各有序vector的当前首元素,每次取堆顶加入结果,再从对应vector取下一个元素入堆,直到所有元素处理完。但实际出错大概率是这些细节没做好:
常见坑点&修复方案:
- 堆里只存了元素值,没记录来源vector:如果只放值,取完堆顶后根本不知道该从哪个vector取下一个元素,这是最容易犯的错。
- 没处理空vector:如果输入的某个vector是空的,初始化堆时直接跳过它,不然会访问非法迭代器。
- 堆的比较逻辑搞反了:C++的
priority_queue默认是最大堆,你需要自定义比较器把它改成最小堆。 - 迭代器越界:每次取完元素后,要检查对应vector的迭代器是否已经到
end(),不能再往堆里塞。
给你一个正确的实现参考,你可以对照自己的代码找差异:
#include <vector> #include <queue> #include <functional> using namespace std; // 堆元素要包含:当前值、当前vector的迭代器、vector的end迭代器 struct HeapElement { int value; vector<int>::iterator curr; vector<int>::iterator end; // 重载>运算符,让priority_queue成为最小堆 bool operator>(const HeapElement& other) const { return value > other.value; } }; void multiway_merge(const vector<vector<int>>& sorted_lists, vector<int>& output_list) { output_list.clear(); // 最小堆:用greater<HeapElement>来反转默认的最大堆逻辑 priority_queue<HeapElement, vector<HeapElement>, greater<HeapElement>> min_heap; // 初始化堆:把每个非空vector的第一个元素入堆 for (const auto& list : sorted_lists) { if (!list.empty()) { min_heap.push({list[0], list.begin(), list.end()}); } } while (!min_heap.empty()) { auto top = min_heap.top(); min_heap.pop(); // 将当前元素加入结果 output_list.push_back(top.value); // 如果当前vector还有下一个元素,继续入堆 ++top.curr; if (top.curr != top.end) { min_heap.push({*top.curr, top.curr, top.end}); } } }
内容的提问来源于stack exchange,提问作者Jordan Ward
相关产品推荐
相关产品推荐

