zoukankan      html  css  js  c++  java
  • Implementation: Quick Sort 2014-08-19

     1 #include <stdio.h>
     2 
     3 void print(int *a, int start , int end);
     4 
     5 void quick_sort(int *a, int start, int end) {
     6     if (start + 1 >= end) return;
     7     int pv = a[start];
     8     int p = start, q = end;
     9     for (;;) {
    10         while (++p < end   && a[p] < pv);
    11         while (--q > start && a[q] > pv);
    12         if (p > q) {
    13             break;
    14         }
    15         int t = a[p];
    16         a[p] = a[q];
    17         a[q] = t;
    18     }
    19 
    20     a[start] = a[p-1];
    21     a[p-1] = pv;
    22     
    23     // print(a, start, end);
    24 
    25     quick_sort(a, start, p-1);
    26     quick_sort(a, p, end);
    27 }
    28 
    29 void print(int *a, int start , int end) {
    30     for (int i=start; i<end; i++) {
    31         printf("%d ", a[i]);
    32     }
    33     printf("
    ");
    34 }
    35 
    36 int main() {
    37     int a[] = {2};
    38     
    39     int len = sizeof(a) / sizeof(int);
    40     quick_sort(a, 0, len);
    41 
    42     for (int i=0; i<len; i++) {
    43         printf("%d ", a[i]);
    44     }
    45     return 0;
    46 }

    快排还是很容易写错的,记得编程珠玑上说,在提出后的十几年时间少有正确的实现,不断尝试感觉这个实现可以作为自己的模板了,或许可以再加上一个随机化选择的过程。

    函数对a[start, end)范围内的数进行一个非降序排序,这个界限划分符合STL的习惯,发现这种半开区间的表示方法确实非常好用

    先选取a[start]作为一个哨兵,对剩下的a(start, end)范围内数进行一个比较交换工作,这样从前到后和从后到前的过程就对称了(现在都是开边界了)

    设 p = start, q=end为初始状态

    在交换过程中

    while (++p < end && a[p] < pv);
    while (--q > start && a[q] > pv);

    首先对下标进行一个自增/自减,这里每次检测都进行这个过程(即使&&后面的条件不满足,防止两个下标在等值处不能移动造成死循环)

    当退出循环时,可以确定p指向的是第一个比哨兵值(a[start])大的元素的下标(有可能这个下标是end,但我们不会直接用它来取值,所以没关系),因而a[p-1]肯定比哨兵值来的小,于是把哨兵值和a[p-1]做一个交换。此时原来的数组已经以a[p-1]为界限被划分成了两部分,a[start, p-1) < a[p-1] < a[p, end)。这样进行一个递归调用即可。

    quick_sort(a, start, p-1);
    quick_sort(a, p, end);

    今天是8月6日,一晃,一年过去了。虽然说上面的方法比较快(采用了双指针),但是练习理解的话还是参照《算法导论》里讲快排的那部分来的比较容易

    size_t partition(vector<int>& nums, size_t start, size_t end) {
        if (start >= end) {
            return start;
        }
        
        int pv = nums[end - 1];
        size_t div = start;
        
        for (size_t i=start; i<end - 1; i++) {
            if (nums[i] < pv) {

                   swap(nums[i], nums[div++]);

            }
        }
        swap(nums[end - 1], nums[div]);
        return div;
    }
    
    
    void quick_sort(vector<int>& nums, size_t start, size_t end) {
        if (start >= end) {
            return;
        }
        size_t div = partition(nums, start, end);
        quick_sort(nums, start, div);
        quick_sort(nums, div+1, end);
    }

    partition 函数中[start,div)区间是比pv小的,[div,i)区间是大于等于pv的,[i, end-1)部分是未知大小的(如果区间截止未知大于等于开始未知,则认为这个区间为空),只要记住这个就可以非常稳定的写出代码,不会如第一种要注意太多细节问题。

  • 相关阅读:
    浮动元素的应用
    网页中选中文字 ,复制的颜色会变化
    JVM指令重排
    JVM相关的几个基本概念
    Cygwin安装apt-cyg
    MySql四种隔离级别
    Django利用form进行显示
    Django在不启动server的情况下调用方法
    Js实现hashMap
    Js编写的菜单树
  • 原文地址:https://www.cnblogs.com/lailailai/p/3922805.html
Copyright © 2011-2022 走看看