使用一个指针的快排,代码分析部分有个问题
JuneYuan opened this issue · comments
笔记:basics_sorting/quick_sorting.md
比较alist[i]和alist[l]时只能使用<而不是<=! 因为只有取<才能进入收敛条件,<=则可能会出现死循环,因为在=时第一个元素可能保持不变进而产生死循环。
我分析写 <=
并不会出现死循环,用这种方式提交了 leetcode 215 题 Kth Largest Element in an Array, 也能通过~
215题代码如下
class Solution {
public int findKthLargest(int[] A, int k) {
if (A == null || A.length == 0) {
return -1;
}
return qSort1(A, 0, A.length - 1, k);
}
private int qSort1(int[] A, int lo, int hi, int k) {
// lo should not be greater than hi
if (lo >= hi) {
return A[hi];
}
// index m of A
int m = lo + 1;
for (int i = lo + 1; i <= hi; i++) {
if (A[i] >= A[lo]) {
swap(A, m++, i);
}
}
swap(A, lo, --m);
if (m + 1 == k) {
return A[m];
} else if (m + 1 > k) {
return qSort1(A, lo, m - 1, k);
} else {
return qSort1(A, m + 1, hi, k);
}
}
private void swap(int[] A, int i, int j) {
int tmp = A[i];
A[i] = A[j];
A[j] = tmp;
}
}
使用两个指针,这段表述好像也要斟酌下~
对于仅使用一个索引进行 partition 操作的快排对于随机分布数列的效果还是不错的,但若数组本身就已经有序或者相等的情况下,每次划分仅能确定一个元素的最终位置,故最坏情况下的时间复杂度变为
$$O(n^2)$$ . 那么有什么办法尽可能避免这种最坏情况吗?聪明的人类总是能找到更好地解决办法——使用两个索引分别向右向左进行 partition.
在原数组已经有序的情况下,one index for partition
和 Two-way partitioning
的复杂度应该都会退化为 O(n^2) 吧,后者相对于前者的优化,我理解应该只是提高了 partition 的效率呢。
我分析写 <= 并不会出现死循环,用这种方式提交了 leetcode 215 题 Kth Largest Element in an Array, 也能通过~
出现死循环应该是有条件的,这段笔记有点历史了,我这周抽空看看能不能找几个例子出来。
后者相对于前者的优化,我理解应该只是提高了 partition 的效率呢
这个你说的可能是对的,我今晚回去再看看这一段,毕竟时间复杂度分析不能以某一种特殊情况评价
你说的都是对的呐~
第一个 等于号 如果用了 for 控制边界,后面递归不包含 m, 确实不会死循环。
第二个在最坏情况(自然有序)仍然会退化为 O(n^2) 只是能优化 partition 效率减少 swap 次数
我等会就改一下,谢谢指出问题
P.S. kth largest number 是个好题,出镜率挺高的
哈,我也是因为在翻英文题解,所以才看的比平常仔细~
自己去写这些东西的时候才会发现,写文档,尤其是要写清晰的文档,真是累