数据结构与算法基础(王卓)(35):交换排序之快排【第二阶段:标准答案、初步发现问题】
目录
第二阶段:一分为二
整个快排算法的程序运行大框架:
做出的改动(和原来程序的区别):
Project 1:
PPT标准答案:
Project 1小问题:
Project 1还存在着一个巨大的问题:
具体问题:
具体深挖解决问题建下节
第二阶段:一分为二
分别对该表划分为的两个子表分别进行该遍历排序操作,再划分为更细分的子表
直至子表单位为1(一个元素)为止
没错,他说的也有道理,我上面写的操作,
其实只能对整张表的第一个元素进行操作,未免有些不太灵活
按他的思路基于上面写的程序进行修改,并补充完整快排算法的整个框架程序:
整个快排算法的程序运行大框架:
- 确定中枢
- 对前半个表进行遍历(嵌套递归我们对整个表的算法操作)
- 对后半个表进行遍历
做出的改动(和原来程序的区别):
传入int low,int high两个元素:
确定(限制)整个程序该循环内所能进行操作改动的范围
L.r[0]初值改为 L.r[low]:
让这个遍历的函数变得更加灵活,不必每次都只能对第一个元素进行比较遍历
函数的功能定制为:
- 操作的数据范围为:high到low
- 用来作为程序比较遍历的对象为:传入的low的初值
Project 1:
int 遍历(SqList &L, int low, int high)
{
L.r[0] = L.r[low];
while (low < high)
{
if (L.r[high].key < L.r[0].key)
{
L.r[low] = L.r[high];
low++;
}
else
high--;
if (L.r[0].key < L.r[low].key)
{
L.r[high] = L.r[low];
high--;
}
else
low++;
}
L.r[low] = L.r[high] = L.r[0];
return low;
}
void QuickSort(SqList& L, int low, int high)
{
int pivot = 遍历(L, low, high);
QuickSort(L, low, pivot-1);
QuickSort(L, pivot + 1, high);
}
然后这个时候我本以为我们写的已经差不多了,然后去看了一下标准答案:
PPT标准答案:
int Partition(SqList& L, int low, int high)
{
L.r[0] = L.r[low]; //复制到哨兵位置
KeyType pivotkey = L.r[low].key;
while (low < high)
{
while (low < high && L.r[high].key >= pivotkey)
high--;
L.r[low] = L.r[high];
while (low < high && L.r[low].key < pivotkey)
low++;
L.r[high] = L.r[low];
}
L.r[low] = L.r[0];
return low;
}
void QuickSort(SqList& L, int low, int high) {
if (low < high)
{
int pivotloc = Partition(L, low, high); //将L一份为二
QuickSort(L, low, pivotloc - 1); //对低子表递归排序
QuickSort(L, pivotloc + 1, high); //对高子表递归排序
}
}
OK,本来我也觉得不以为然,乍一看没什么大问题了,只剩下一个无伤大雅的
Project 1小问题:
补充条件语句:快排要求必须 (low < high)
结果到整的去尝试了一下带入实例了以后发现
Project 1还存在着一个巨大的问题:
具体问题:
运行逻辑机制问题,我们就拿PPT上的实例来说事吧:
将逐次具体操作转化为表格展示如下:
第几步 | 操作 | Low指向 | High指向 |
第1步 | 49变哨兵 | 1 | 8 |
第2步 | 49'不动,high--(第一个 if / else 判断) | 1 | 7 |
第3步 | 49不动,low++(第二个 if / else 判断) | 2 | 7 |
这里到了第三步,明显就开始出问题了:
空格里面还没有元素呢,你这个算法就开始超过他、跳跃到下一格,干什么?
重复比较无伤大雅,但是low移动了,危险!!!(要出错了)
这里很明显,我们可以看到,问题出在:
在第一个处理的元素被放到哨兵里后,我们又去拿这个元素本身比较哨兵
也就是自己比较自己,错过了这个空格;
而不是用这个空格来装第一个小于哨兵的元素