算法的一个关键组成部分是所选的枢轴值来自原始列表,这意味着(在您的情况下)具有值
5
的元素现在在第一次分区后处于正确的最终位置:
4 3 2 5 9 11 8 12 6 10 7
这应该是相当明显的,遵循简单的直觉。如果一个项目左侧的每个元素都小于该项目,并且右侧的每个元素都大于该项目,则该项目必须处于正确的排序位置。
理解整个快速排序算法所需的洞察力在于,您可以将此操作应用于每个子列表 - 枢轴左侧的值列表和包含所有值的列表 - 以到达最终排序的列表。这是因为:
- 每个分区将一个以上的元素放置在其适当的位置
- 每次迭代从要处理的元素列表中删除一个元素 - 枢轴 - (这就是为什么我们最终会达到零(或一个,具体取决于您如何执行)元素的基本情况)
假设您根据以下伪代码选择了分区值5
:
Math.floor(list.length / 2)
对于我们的目的,实际上选择一个枢轴并不重要。这个可以适用于您最初的选择,所以我们将使用它。现在,让我们一直玩到最后(从您离开的地方开始):
concat(qs([4 3 2]), 5, qs([9 11 8 12 6 10 7])) =
concat(qs([2]), 3, qs([4]), 5, qs([9, 11, 8, 6, 10, 7]), 12, qs([])) =
concat(2, 3, 4, 5, qs([6, 7]), 8, qs([9, 11, 10]), 12) =
concat(2, 3, 4, 5, qs([6]), 7, qs([]), 8, qs([9, 10]), 11, qs([]), 12) =
concat(2, 3, 4, 5, 6, 7, 8, qs([9]), 10, qs([]), 11, 12) =
concat(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
请注意,每次您看到对
qs
的单个调用时,它都会遵循以下模式:
qs(<some_left_list>), <the_pivot>, qs(<some_right_list>)
每次在一行上调用qs
都会导致以下一行上进行两个以上的这样的调用(表示处理两个新子列表,除非注意到我立即对单值列表上的qs
调用进行分解)。
自己完成这个练习是一个好主意。是的,用实际的笔和纸。