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



    活动地址:CSDN21天学习挑战赛

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

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

    🔑前言

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

    非递归:

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

    1. 数组头尾索引入栈
    2. 栈不为空,则头尾索引出栈,分别赋予 lo 和 hi,对这一范围内的元素进行 partition,得到枢纽索引 key_pos;栈空,则排序结束。
    3. 如果左侧数组长度不为 1,则数组头尾索引入栈;如果为 1 则什么也不做。右侧数组一样。
    4. 回到第 2 步。
    #include
    #include
    #include
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    应用:螺丝和螺帽。(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
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    内循环优化: 修改快速排序算法,去掉内循环 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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
  • 相关阅读:
    【课程作业】西瓜书 机器学习课后习题 : 第三章
    java SpringBoot 自己写的类 调用 service 层的方法
    Python自动化办公【自动组织文件】
    RabbitMQ—持久化
    robots.txt漏洞
    关键字extern、static与const
    南非 KMP 媒体集团实施了 DMS(文档管理系统)使流程数字化,员工可以再次专注于他们的实际任务,提供了效率
    Java · 链表相关练习题 · 高频面试题 · 有难度啊
    315.计算右侧小于当前元素的个数
    hive的分组和组内排序
  • 原文地址:https://blog.csdn.net/weixin_45773137/article/details/126407866