这里的霍尔法内容来自文章:【排序算法】快速排序(C语言)_c语言快速排序-CSDN博客
霍尔法
单趟排序使用霍尔法,这样的话我们必须保证除了指针停留的位置到头之外,最后首尾指针共同指向的是一个比key小的值,所以我们的做法是让右指针先移动,因为right
找比key
小的值,所以此时right
的位置一定比key小。
这种方法思路上最为简单,但不太好的原因在于最后那个值很可能是一个与上一轮挑出来要插入的值很接近的,那么直接将它放到左边一半的话,左边这个区间进行一趟排序操作之时很可能遇到的情况是分了等于没分,因为选定要插入的值往往是第一个,而这里的第一个又是一个与上一轮中第一个数很接近的数,即为左边区间的最大值,那么自然分了几乎等于没分(选择了划分效率最低的情况),因为我们理想的划分情况是希望能划分的数是当前区间的中值元素,这样能尽可能将区间划分成的左右区间尽可能数量相等。
当然这个也是可以解决的,就是我们不要选定插入的值为当前序列的第一个值,可以选择为插入的值为当前序列的中间值。这样也可以完美解决问题。
蛮横小公主法
当然我们也有别的方法来使得,在每次选定插入的值可以是第一个的方法,下面展示它的一趟操作步骤,为了便于记忆我将她叫做(蛮横小公主法),书上没有定义它的名字,起名原因在后面。
题目:待排列的表中有10个元素,关键字的集合为{38,30,50,16,35,76,48,44,28,31},下面是描述第一趟排序的过程示意图
可以看到这里面定义了两个指针i,j分别指向首尾元素,还有一个temp变量,用来保存第一个元素,也就是我们要插入到中间的元素,这个变量我们可以看到仅仅在一开始保存一下第一个元素,然后在最后恢复一下,中间过程和temp变量无关。
具体过程:
右指针j先开始向左遍历,找到比temp小的元素停下来,然后将这个值复制到左指针i指向的元素,相当于直接覆盖掉原来的元素值(你可能很震惊,先看下去),然后右指针停下来,左指针向右移动,当左指针找到比temp大的元素时,同样将左指针指向的元素复制到右指针指向的,相当于直接覆盖掉原来的元素值。然后左指针停止右指针开始像左边移动,重复上述过程,直到左指针和右指针重合i==j,停止,然后将temp的值赋值回i和j共同指向的位置。
接下来解释一下上面操作,为什么可以直接覆盖,其实覆盖的时候我们只是将一个覆盖掉了,而且是将不合适位置上的的这个重复值给覆盖掉了,比如看下面图中以50覆盖31,就是覆盖的31错误的位置,31在左侧还有一份,在正确合适的位置而存在着。而每次我们覆盖后,那个停下来的指针其实都指向的是一个应该被删除的元素。最终两个指针指向同一个位置,这个位置也是应该被删除的重复元素,此时以temp来覆盖。那你可能还有一个疑问第一次覆盖的时候38就被直接覆盖掉了,38在序列中就不存在了,确实是这样,但是我们一开始就将序列第一个元素存在了temp中,而且你会发现因为是右指针首先移动,所以第一个被覆盖的元素肯定是第一个位置上元素,所以这个算法是合理的。
这个算法乍一下看上去确实可能比较复杂,但是看懂了之后你会觉得这个算法其实思路上很顺畅。至于为什么我叫她蛮横小公主,因为她相比上一个来说会直接覆盖掉另一个指针指向的元素,实在是太蛮横了。大家可以结合我右边用线连起来的这个图来思考。这样流程就很清晰了。