快速排序的非递归形式和一个小应用


活动地址:优快云21天学习挑战赛

📚“九层之台,起于垒土”。学习技术须脚踏实地。

☀️你要做冲出的黑马,而不是坠落的星星。

🔑前言

本文为算法(第四版)的题目记录,主要练习快速排序,主要记录快速排序一节的习题。
这里推荐一款刷题、模拟面试神器,可助你斩获心仪大厂offer:点我免费刷题、模拟面试

非递归:

栈往往是取代递归的最好数据结构,快速排序中我们也可以利用栈来取代递归,具体步骤如下:

  1. 数组头尾索引入栈
  2. 栈不为空,则头尾索引出栈,分别赋予 lo 和 hi,对这一范围内的元素进行 partition,得到枢纽索引 key_pos;栈空,则排序结束。
  3. 如果左侧数组长度不为 1,则数组头尾索引入栈;如果为 1 则什么也不做。右侧数组一样。
  4. 回到第 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 个螺帽混在一堆,你需要快速将它们配对。一个螺丝只会匹配一个螺帽,一个螺帽也只会匹配一个螺丝。你可以试着把一个螺丝和一个螺帽拧在一起看看谁大了,但不能直接比较两个螺丝或者两个螺帽。给出一个解决这个问题的有效方法。

解法:这是快速排序的典型应用,螺帽螺丝相互分区即可使螺丝螺帽分别有序。
具体步骤:

  1. 用螺丝把螺母分区,得到三个区:

    • A1:小于螺丝;

    • A2:等于螺丝,含一个螺母;

    • A3:大于螺丝。

  2. 用 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);
}
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

进击的博仔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值