我正在提高我的算法知识,阅读Robert Sedgewick的“算法”一书并完成练习。我遇到了困难:
执行Quick.sort()期间的最大次数是多少 对于长度为N?
的数组,可以交换最大的项目
我已经通过实验确定,假设数组中的所有元素都是不同的,则最大项的最大交换次数为floor(N/2)
。 如何以数学方式证明这一点?如果我错了,我的错误是什么?
我发现了几个关于这个问题的提及(例如this one),但答案与我的结果不符。那些答案表明最大数量是N-1
,但我无法找到这样的数组,当我使用我的快速排序对它进行排序时,它会给我最大的N-1
个最大项目的交换版本(见下文)。
我使用的快速排序代码:
template<typename BiDirIterator, typename Compare = std::less<typename BiDirIterator::value_type>>
BiDirIterator partition(BiDirIterator begin, BiDirIterator end, Compare compare = Compare())
{
auto partition_item = begin;
while (true)
{
while (++begin != end && !compare(*partition_item, *begin));
while (begin != end && !compare(*--end, *partition_item));
if (begin == end)
break;
std::iter_swap(begin, end);
}
if (partition_item != --begin)
std::iter_swap(partition_item, begin);
return begin;
}
template<typename BiDirIterator, typename Compare = std::less<typename BiDirIterator::value_type>>
void quicksort(BiDirIterator begin, BiDirIterator end, Compare compare = Compare())
{
if (begin == end || std::next(begin) == end)
return;
auto pos = partition(begin, end, compare);
quicksort(begin, pos, compare);
quicksort(++pos, end, compare);
}
我用来计算最终项目的交换次数的代码:
struct exchange_counter
{
exchange_counter(int value)
: value(value)
{
}
int value;
int number_of_exchanges = 0;
exchange_counter(const exchange_counter& other) = default;
exchange_counter& operator=(const exchange_counter& other) = default;
exchange_counter(exchange_counter&& other) = default;
exchange_counter& operator=(exchange_counter&& other)
{
value = other.value;
number_of_exchanges = other.number_of_exchanges + 1;
return *this;
}
friend bool operator<(const exchange_counter& left, const exchange_counter& right) noexcept
{
return left.value < right.value;
}
friend bool operator==(const exchange_counter& left, const exchange_counter& right) noexcept
{
return left.value == right.value;
}
};
for (int i = 1; i != 15; ++i)
{
std::vector<exchange_counter> values;
for (int j = 0; j != i; ++j)
values.emplace_back(j);
auto max_element = i - 1;
auto max_number_of_exchanges = 0;
do
{
for (auto& value : values)
value.number_of_exchanges = 0;
auto copy = values;
quicksort(copy.begin(), copy.end());
max_number_of_exchanges = (std::max)(max_number_of_exchanges,
std::find(copy.begin(), copy.end(), max_element)->number_of_exchanges);
}
while (std::next_permutation(values.begin(), values.end()));
std::cout << "Elements: " << i << "; max exchanges: " << max_number_of_exchanges << std::endl;
}
PS。如果我使用相同的方法在Visual Studio 2015中测试std::sort
(实现为快速排序),则最大项目的交换次数为N - 1
。
答案 0 :(得分:3)
每次我们对数组进行分区时,最大项必须移动2个位置,以便最多次交换它。它不能仅移动1个位置,因为在这种情况下它将成为枢轴元素并将移动到其最终位置。例如,请考虑以下数组:
4 10 3 x x x ...
P i j
对数组进行分区后,最大元素(10)向右移动1个位置
3 4 10 x x x ...
P
但是现在最大的项目变成了一个枢轴元素,并且将被移动到数组的末尾,只添加一个交换。
相反,我们需要安排这些项目,以便最大的项目移动2个位置,保持前面的1个项目成为枢轴元素:
2 10 4 1 x x x ...
P i j
分区后:
1 2 4 10 x x x ...
P i j
最大的项目每次移动2个位置,因此交换的数量是下限(N / 2)。
示例(N = 10)
2 10 4 1 6 3 8 5 7 9
在这种情况下,最大项目(10)的最大交换次数为5次。
答案 1 :(得分:0)
您对该问题的回答并不准确。最大数量不能超过可用空间的次数,因为它应该始终接近正确的位置。因此,从第一个值到最后一个值点,它将被交换N次。 对于这种情况有一个排除,即当数组的大小为1时,最大元素不能再移动,因此最大移动次数为N - 1.
此答案之前已在此处提供:Scenarios for selection sort, insertion sort, and quick sort