介绍
快速排序是数列排序的经典算法之一,与其他的算法相比,它的特点是数字的比较和交换次数少,在许多情况下可以高速进行排序。
事例
接下来本文展示3、5、8、1、2、9、4、7、6快速排序为从小到大的算法流程。
首选对数列中所有数字视为第一轮操作的对象,选择一个数字作为排序基准,这个数字为pivot,接下来用P来表示。
P通常随机从数列中选一个数字。为了方便起见,我们选择最右边的数字。接下来,在最左边的数字上标记左标记L,最右边的在数字上标记右标记R。
快速排序是一种使用标记递归地重复一系列操作的算法。
向右移动左标记,当左标记的数值大于P标记的数字时,停止移动(8大于6)。
向左移动右标记,当右标记的数值小于P标记的数字时,停止移动(4小于6)。
当L和R标记都停止时,交换L和R标记的数字,交换后L和R恢复行动。
整理一下目前的操作所得的结论,左标记L的作用是找到一个大于P的数字,而右标记的作用时找到一个小于P的数字。通过数字交换可以在数列的左侧收集小于pivotP的数字,右侧收集大于pivotP的数字。
L和R恢复行动,L继续向右移动,找大于P标记的数字时。
L找到9大于6停下。然后向左移动R。
R一直向左移动,寻找小于P标记的数过程中,碰到了L,停止了移动。
此时,L和R标记都停止,并在同一个位置指向6。在这种情况下,L和R标记共同指向的数字9和P指向的数字6交换。交换后,L和R标记共同指向6,此时6排序完成,确定位置。第一轮操作完成。
经过第一轮操作,我们完成了P标记第一轮数值6的排序,并把小于6的数字放在了它左边,大于6的数字放到了它右边。现在数列分为两部分3、5、4、1、2和8、7、9。接下来递归地对这两部分数列执行如同第一轮的操作。
先操作3、5、4、1、2:
P标记最右的2,L和R分别标记3和1。因为3大于2,1小于2,所以L和R停止移动并交换相方标记的数字。
交换完成后,L和R继续移动,L向右移动到5,大于P指向的2,停止移动。
R向左移动,直到与L相遇,也没再找到比P指向的2更小的数,此时L和R标记共同指向5。
L和R标记共同指向的数字与P指向交换,此时2完成了排序。
数列再次分为两部分1和4、3、5。
完成了第二轮操作,确定了2在排序中的位置,并继续再次把子数列分成两部分。如果操作数列只有1个数字,则也认为已完成排序,此时1排序位置也已经确立。
接下来操作4、3、5。
P标记最右的5,L标记4,R标记3。
L向右移动,寻找比P标记的5大的数,与R相遇,值得注意的是,L与R相遇,并不会停止行动,而是会经过R后继续向右移动。
L继续向右移动,与P相遇,此时L停止行动,确立了P所标记的5是当前子队列中的最大值。本轮排序结束,5的位置确立。
操作4、3子队列...
...
此后,重复相同的操作,直到所有的数字完成排序,此文不一一画出。最终完成了1~9点数字排序。
总结
快速排序主要通过三个标记P、L、R对数列按规则做出交换操作,得出排序结果和子数列后继续递归操作。
- 在从小到大的排序中,
L从左往右寻找比P大的数,R从右往左寻找比P小的数。先操作完L再操作R,L寻找到目标或与P相遇时停下来,R寻找到模板或与L相遇时停下来。 - 当
L和R都停下来,并且还没相遇时,交换L和R彼此的数字,继续重复L与R的操作。 - 当
R碰到L停下来时候,交换LR共同标记的数字与P标记的数字后,完成一次排序,确立LR次数标记的数字,并以LR此时标记数字划分左侧和右侧两个新数列,继续递归标记操作。 - 当
L碰到P停下来时候,完成一次排序,确立LP此时标记的数字,并以左侧数列继续递归标记操作。