快速排序写法
双指针写法 递归
template <typename Comparable>
int partition(vector<Comparable>& v, int left, int right) {
if (left >= right) return left;
int i = left, j = right;
Comparable pivot = v[left];
while (i < j) {
while (i < j && !(v[j] < pivot)) j--;//注意这里的判断条件,和下面的区别
v[i] = v[j];
while (i < j && v[i] < pivot) i++;
v[j] = v[i];
}
v[i] = pivot;
return i;
}
template <typename Comparable>
void quicksort1(vector<Comparable>& v, int left, int right) {
if (left >= right) return;
int mid = partition(v, left, right);
quicksort1(v, left, mid - 1);
quicksort1(v, mid + 1, right);
}
借用栈 非递归
template <typename Comparable>
void quicksort2(vector<Comparable>& v, int left, int right) {
if (left >= right) return;
stack<int> s;
s.push(left);
s.push(right);
//用栈保存每一个待排序子串的首尾元素下标,下一次while循环时取出这个范围,对这段子序列进行partition操作
while (!s.empty()) {
int right = s.top();
s.pop();
int left = s.top();
s.pop();
if (left < right) {
int boundary = partition(v, left, right);
// 左区间
s.push(left);
s.push(boundary - 1);
// 右区间
s.push(boundary + 1);
s.push(right);
}
}
}
性能比较
实际上这里,递归算法快于非递归算法。
借用栈或队列将递归算法改为非递归,不一定会带来好处。
快速排序和冒泡排序
共同点:
- 都要经历n趟排序。
- 每趟排序要经历O(n)次比较。
- 都是后半部分元素比前半部大。
不同点:
- 冒泡排序的交换操作发生相邻的元素之间,即一趟排序要经过多次交换操作。
- 快速排序的交换操作发生在间隔比较远的两个元素之间,一趟排序要经过交换操作次数会少一些。
- 冒泡是稳定的,快排是不稳定的。