快速排序算法的最大和最小交换量
Posted
技术标签:
【中文标题】快速排序算法的最大和最小交换量【英文标题】:Maximum and minimum amont of swaps for Quicksort Algoritm 【发布时间】:2022-01-01 02:26:36 【问题描述】:我的作业中有以下内容:
考虑快速排序算法。
我。举一个需要最大交换操作次数的 8 元素数组的例子 (假设枢轴是第一个元素),并解释你的答案。
二。举一个需要最少交换操作次数的 8 元素数组的例子(假设枢轴是最后一个元素),并解释你的答案。
我认为需要最少交换操作次数的数组是已经排序的数组 1,2,3,4,5,6,7,8,因为不会有任何交换。但是对于第一部分,除了编写代码和暴力破解之外,我不知道如何处理它。解决这个问题的正确方法是什么?
【问题讨论】:
您认为快速排序“最难”处理的值的布局是什么?考虑一个更简单的情况,例如只有 3 个值的数组(它足够小,您可以在论文中快速绘制所有可能的情况)。 @devouredelysium:IMO,3 个元素的情况太小了,看不到模式。 暴力破解有什么问题,并提供您的程序作为解释? @trincot 我没有程序我必须在纸上解决这个问题并解释我是如何做到的。 @trincot:这确实是可行的。 40230 个案例可供尝试。 【参考方案1】:我会通过编程来做到这一点:
产生 [1,2,3,4,5,6,7,8] 的所有可能排列 计算需要多少交换才能对它们进行排序 保留一个使计数最大化的人此外,您还可以对该结果再次执行排序,并输出所有已进行的交换。
结果将取决于分区算法。下面是 javascript 中的一个实现,它为 Lomuto 分区方案和 Hoare 分区方案执行上述算法(两者都被更改为以左值作为枢轴)。
你可以在这里运行它:
霍尔
function quickSortHoare(arr, start=0, end=arr.length, verbose=false)
if (verbose) console.log("quickSortHoare(" + arr.map((val, i) => i >= start && i < end ? val : "-").join(" ") + ")");
let count = 0;
if (end - start < 2) return 0;
let pivot = arr[start];
let i = start - 1, j = end;
while (true)
do i++ while (arr[i] < pivot);
do j-- while (arr[j] > pivot);
if (i >= j) break;
if (verbose) console.log(" swap values " + arr[i] + " and " + arr[j]);
[arr[i], arr[j]] = [arr[j], arr[i]];
count++;
if (verbose) console.log(" after partitioning: " + arr.map((val, i) => i >= start && i < end ? val : "-").join(" "));
if (i == start) i++;
return count + quickSortHoare(arr, start, i, verbose) + quickSortHoare(arr, i, end, verbose);
function* permutations(arr)
if (arr.length <= 1) yield arr;
else
let value = arr[0];
for (let perm of permutations(arr.slice(1)))
for (let i = 0; i < arr.length; i++)
yield perm.slice(0, i).concat(value, perm.slice(i));
function findWorstCase(sorter)
let arr = [1, 2, 3, 4, 5, 6, 7, 8];
let worstCase;
let maxCount = -1;
for (let perm of permutations(arr))
let count = sorter([...perm]);
if (count > maxCount)
maxCount = count;
worstCase = perm;
console.log(...worstCase);
sorter(worstCase, 0, worstCase.length, true);
console.log(maxCount + " swaps");
console.log("Hoare partitioning:");
findWorstCase(quickSortHoare);
发现的结果是,使用Hoare partition scheme 和最左边的值作为枢轴对 [5, 6, 8, 7, 2, 1, 4, 3] 进行排序需要 11 次交换:
Hoare partitioning:
5 6 8 7 2 1 4 3
quickSortHoare(5 6 8 7 2 1 4 3)
swap values 5 and 3
swap values 6 and 4
swap values 8 and 1
swap values 7 and 2
after partitioning: 3 4 1 2 7 8 6 5
quickSortHoare(3 4 1 2 - - - -)
swap values 3 and 2
swap values 4 and 1
after partitioning: 2 1 4 3 - - - -
quickSortHoare(2 1 - - - - - -)
swap values 2 and 1
after partitioning: 1 2 - - - - - -
quickSortHoare(1 - - - - - - -)
quickSortHoare(- 2 - - - - - -)
quickSortHoare(- - 4 3 - - - -)
swap values 4 and 3
after partitioning: - - 3 4 - - - -
quickSortHoare(- - 3 - - - - -)
quickSortHoare(- - - 4 - - - -)
quickSortHoare(- - - - 7 8 6 5)
swap values 7 and 5
swap values 8 and 6
after partitioning: - - - - 5 6 8 7
quickSortHoare(- - - - 5 6 - -)
after partitioning: - - - - 5 6 - -
quickSortHoare(- - - - 5 - - -)
quickSortHoare(- - - - - 6 - -)
quickSortHoare(- - - - - - 8 7)
swap values 8 and 7
after partitioning: - - - - - - 7 8
quickSortHoare(- - - - - - 7 -)
quickSortHoare(- - - - - - - 8)
11 swaps
洛穆托
这里是同样的东西,但使用基于 Lomuto 的分区:
function quickSortLomuto(arr, start=0, end=arr.length, verbose=false)
if (verbose) console.log("quickSortLomuto(" + arr.map((val, i) => i >= start && i < end ? val : "-").join(" ") + ")");
let count = 0;
if (end - start < 2) return 0;
let pivot = arr[start];
let i = end;
for (let j = end - 1; j >= start; j--)
if (arr[j] >= pivot)
i--;
if (i != j)
if (verbose) console.log(" swap values " + arr[i] + " and " + arr[j]);
[arr[i], arr[j]] = [arr[j], arr[i]];
count++;
if (verbose) console.log(" after partitioning: " + arr.map((val, i) => i >= start && i < end ? val : "-").join(" "));
return count + quickSortLomuto(arr, start, i, verbose) + quickSortLomuto(arr, i + 1, end, verbose);
function* permutations(arr)
if (arr.length <= 1) yield arr;
else
let value = arr[0];
for (let perm of permutations(arr.slice(1)))
for (let i = 0; i < arr.length; i++)
yield perm.slice(0, i).concat(value, perm.slice(i));
function findWorstCase(sorter)
let arr = [1, 2, 3, 4, 5, 6, 7, 8];
let worstCase;
let maxCount = -1;
for (let perm of permutations(arr))
let count = sorter([...perm]);
if (count > maxCount)
maxCount = count;
worstCase = perm;
console.log(...worstCase);
sorter(worstCase, 0, worstCase.length, true);
console.log(maxCount + " swaps");
console.log("Lomuto partitioning:");
findWorstCase(quickSortLomuto);
结果是最坏的情况 [2, 4, 6, 8, 7, 5, 3, 1] 需要 16 次交换:
Lomuto partitioning:
2 4 6 8 7 5 3 1
quickSortLomuto(2 4 6 8 7 5 3 1)
swap values 1 and 3
swap values 1 and 5
swap values 1 and 7
swap values 1 and 8
swap values 1 and 6
swap values 1 and 4
swap values 1 and 2
after partitioning: 1 2 4 6 8 7 5 3
quickSortLomuto(1 - - - - - - -)
quickSortLomuto(- - 4 6 8 7 5 3)
swap values 3 and 5
swap values 3 and 7
swap values 3 and 8
swap values 3 and 6
swap values 3 and 4
after partitioning: - - 3 4 6 8 7 5
quickSortLomuto(- - 3 - - - - -)
quickSortLomuto(- - - - 6 8 7 5)
swap values 5 and 7
swap values 5 and 8
swap values 5 and 6
after partitioning: - - - - 5 6 8 7
quickSortLomuto(- - - - 5 - - -)
quickSortLomuto(- - - - - - 8 7)
swap values 7 and 8
after partitioning: - - - - - - 7 8
quickSortLomuto(- - - - - - 7 -)
quickSortLomuto(- - - - - - - -)
16 swaps
分区方案有很多变体,它们会影响最坏的情况。
【讨论】:
以上是关于快速排序算法的最大和最小交换量的主要内容,如果未能解决你的问题,请参考以下文章