活动地址:优快云21天学习挑战赛
📚“九层之台,起于垒土”。学习技术须脚踏实地。
☀️你要做冲出的黑马,而不是坠落的星星。
🔑前言
本文为算法(第四版)的题目记录,主要练习快速排序,主要记录快速排序一节的习题。
这里推荐一款刷题、模拟面试神器,可助你斩获心仪大厂offer:点我免费刷题、模拟面试
非递归:
栈往往是取代递归的最好数据结构,快速排序中我们也可以利用栈来取代递归,具体步骤如下:
- 数组头尾索引入栈
- 栈不为空,则头尾索引出栈,分别赋予 lo 和 hi,对这一范围内的元素进行 partition,得到枢纽索引 key_pos;栈空,则排序结束。
- 如果左侧数组长度不为 1,则数组头尾索引入栈;如果为 1 则什么也不做。右侧数组一样。
- 回到第 2 步。
#include<iostream>
#include<stack>
#include<vector>
using namespace std;
template<typename T>
int partition(T* a, int lo, int hi){
int i = lo, j = hi + 1;
T pivot = a[lo];
while(true){
while(a[++i] < pivot) if(i == hi) break;
while(pivot < a[--j]) ;
if(i >= j) break;
swap(a[i], a[j]);
}
swap(a[lo], a[j]);
return j;
}
template<typename T>
void sort(T* vec, int size){
stack<int> s ;
s.push(0);
s.push(size - 1);
while(!s.empty()){
int hi = s.top(); s.pop();
int lo = s.top(); s.pop();
int key_pos = partition(vec, lo, hi);
if(lo < key_pos - 1){
s.push(lo);
s.push(key_pos - 1);
}
if(hi > key_pos + 1){
s.push(key_pos + 1);
s.push(hi);
}
}
}
int main(){
int vec[10] = {34, 456, 34, 3, 564, 234, 56, 123, 6545, 23};
int i;
cin >> i;
sort(vec, i);
for(auto i: vec) cout << i << ' ';
return 0;
}
应用:螺丝和螺帽。(G. J. E. Rawlins) 假设有 N 个螺丝和 N 个螺帽混在一堆,你需要快速将它们配对。一个螺丝只会匹配一个螺帽,一个螺帽也只会匹配一个螺丝。你可以试着把一个螺丝和一个螺帽拧在一起看看谁大了,但不能直接比较两个螺丝或者两个螺帽。给出一个解决这个问题的有效方法。
解法:这是快速排序的典型应用,螺帽螺丝相互分区即可使螺丝螺帽分别有序。
具体步骤:
-
用螺丝把螺母分区,得到三个区:
-
A1:小于螺丝;
-
A2:等于螺丝,含一个螺母;
-
A3:大于螺丝。
-
-
用 A2 的螺母将螺丝分区,得到三个区:
-
B1:小于螺母;
-
B2:等于螺母;
-
B3:大于螺母。
-
A1与B1对应,A3与B3对应,继续对A1与B1 和 A3与B3使用上述算法,直到所有区的螺丝与螺母数目为一。
c++代码:
#include<iostream>
using namespace std;
int partition(int* m, int* s, int lo, int hi){
int i = lo-1, j = hi + 1;
int s_pivot = s[lo];
while(true){
while(m[++i] < s_pivot) if(i == hi) break;
while(s_pivot < m[--j]) if(j == lo) break;
if(i >= j) break;
swap(m[i], m[j]);
}
i = lo, j = hi + 1;
while(true){
while(s[++i] < s_pivot) if(i == hi) break;
while(s_pivot < s[--j]) if(j == lo) break;
if(i >= j) break;
swap(s[i], s[j]);
}
swap(s[lo], s[j]);
return j;
}
void sort(int* m, int* s, int lo, int hi){
if(hi <= lo) return;
int j = partition(m, s, lo, hi);
sort(m, s, lo, j - 1);
sort(m, s, j + 1, hi);
}
void sort(int* m, int* s, int size){
sort(m, s, 0, size - 1);
}
int main(){
int a[10] = {34, 456, 34, 3, 564, 234, 56, 123, 6545, 23};
int b[10] = {3, 56, 123, 564, 234, 6545, 23, 34, 456, 34};
sort(a, b, 10);
for(auto i : a){
cout << i << " ";
}
cout << endl;
for(auto i : b){
cout << i << " ";
}
cout << endl;
return 0;
}
内循环优化: 修改快速排序算法,去掉内循环 while 中的边界检查。由于切分元素本身就是一个哨兵( v 不可能小于 a[lo] ),左侧边界的检查是多余的。要去掉另一个检查,可以在打乱数组后将数组的最大元素放在 a[length-1] 中。该元素永远不会移动(除非和相等的元素交换),可以在所有包含它的子数组中成为哨兵。注意:在处理内部子数组时,右子数组中最左侧的元素可以作为左子数组右边界的哨兵。
template<typename T>
int partition(T* a, int lo, int hi){
int i = lo, j = hi;
T pivot = a[lo];
while(true){
while(a[++i] < pivot) ;
while(pivot < a[--j]) ;
if(i >= j) break;
swap(a[i], a[j]);
}
swap(a[lo], a[j]);
return j;
}
template<typename T>
void sort(T* a, int lo, int hi){
if(hi <= lo) return;
int j = partition(a, lo, hi);
sort(a, lo, j - 1);
sort(a, j + 1, hi);
}
template<typename T>
void sort(T* a, int size){
int temp = 0;
for(int i = 0;i < a.length;++i){
if(a[temp] < a[i]) temp = i;
}
swap(a[temp], a[size - 1]);
sort<T>(a, 0, size);
}