• 吴裕雄--天生自然数据结构:十大经典排序算法——快速排序


    快速排序
    快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要 Ο(nlogn) 次比较。在最坏状况下则需要 Ο(n2) 次比较,但这种状况并不常见。事实上,快速排序通常明显比其他 Ο(nlogn) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。
    
    快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。
    
    快速排序又是一种分而治之思想在排序算法上的典型应用。本质上来看,快速排序应该算是在冒泡排序基础上的递归分治法。
    
    快速排序的名字起的是简单粗暴,因为一听到这个名字你就知道它存在的意义,就是快,而且效率高!它是处理大数据最快的排序算法之一了。
    在《算法艺术与信息学竞赛》:快速排序的最坏运行情况是 O(n²),比如说顺序数列的快排。但它的平摊期望时间是 O(nlogn),且 O(nlogn) 记号中隐含的常数因子很小,比复杂度稳定等于 O(nlogn) 的归并排序要小很多。所以,对绝大多数顺序性较弱的随机数列而言,快速排序总是优于归并排序。
    1. 算法步骤
    从数列中挑出一个元素,称为 "基准"(pivot);
    
    重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
    
    递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;
    代码实现
    JavaScript
    function quickSort(arr, left, right) {
        var len = arr.length,
            partitionIndex,
            left = typeof left != 'number' ? 0 : left,
            right = typeof right != 'number' ? len - 1 : right;
    
        if (left < right) {
            partitionIndex = partition(arr, left, right);
            quickSort(arr, left, partitionIndex-1);
            quickSort(arr, partitionIndex+1, right);
        }
        return arr;
    }
    
    function partition(arr, left ,right) {     // 分区操作
        var pivot = left,                      // 设定基准值(pivot)
            index = pivot + 1;
        for (var i = index; i <= right; i++) {
            if (arr[i] < arr[pivot]) {
                swap(arr, i, index);
                index++;
            }        
        }
        swap(arr, pivot, index - 1);
        return index-1;
    }
    
    function swap(arr, i, j) {
        var temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
    function partition2(arr, low, high) {
      let pivot = arr[low];
      while (low < high) {
        while (low < high && arr[high] > pivot) {
          --high;
        }
        arr[low] = arr[high];
        while (low < high && arr[low] <= pivot) {
          ++low;
        }
        arr[high] = arr[low];
      }
      arr[low] = pivot;
      return low;
    }
    
    function quickSort2(arr, low, high) {
      if (low < high) {
        let pivot = partition2(arr, low, high);
        quickSort2(arr, low, pivot - 1);
        quickSort2(arr, pivot + 1, high);
      }
      return arr;
    }
    Python
    def quickSort(arr, left=None, right=None):
        left = 0 if not isinstance(left,(int, float)) else left
        right = len(arr)-1 if not isinstance(right,(int, float)) else right
        if left < right:
            partitionIndex = partition(arr, left, right)
            quickSort(arr, left, partitionIndex-1)
            quickSort(arr, partitionIndex+1, right)
        return arr
    
    def partition(arr, left, right):
        pivot = left
        index = pivot+1
        i = index
        while  i <= right:
            if arr[i] < arr[pivot]:
                swap(arr, i, index)
                index+=1
            i+=1
        swap(arr,pivot,index-1)
        return index-1
    
    def swap(arr, i, j):
        arr[i], arr[j] = arr[j], arr[i]
    Go
    func quickSort(arr []int) []int {
            return _quickSort(arr, 0, len(arr)-1)
    }
    
    func _quickSort(arr []int, left, right int) []int {
            if left < right {
                    partitionIndex := partition(arr, left, right)
                    _quickSort(arr, left, partitionIndex-1)
                    _quickSort(arr, partitionIndex+1, right)
            }
            return arr
    }
    
    func partition(arr []int, left, right int) int {
            pivot := left
            index := pivot + 1
    
            for i := index; i <= right; i++ {
                    if arr[i] < arr[pivot] {
                            swap(arr, i, index)
                            index += 1
                    }
            }
            swap(arr, pivot, index-1)
            return index - 1
    }
    
    func swap(arr []int, i, j int) {
            arr[i], arr[j] = arr[j], arr[i]
    }
    C++
    //严蔚敏《数据结构》标准分割函数
     Paritition1(int A[], int low, int high) {
       int pivot = A[low];
       while (low < high) {
         while (low < high && A[high] >= pivot) {
           --high;
         }
         A[low] = A[high];
         while (low < high && A[low] <= pivot) {
           ++low;
         }
         A[high] = A[low];
       }
       A[low] = pivot;
       return low;
     }
    
     void QuickSort(int A[], int low, int high) //快排母函数
     {
       if (low < high) {
         int pivot = Paritition1(A, low, high);
         QuickSort(A, low, pivot - 1);
         QuickSort(A, pivot + 1, high);
       }
     }
    Java
    public class QuickSort implements IArraySort {
    
        @Override
        public int[] sort(int[] sourceArray) throws Exception {
            // 对 arr 进行拷贝,不改变参数内容
            int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);
    
            return quickSort(arr, 0, arr.length - 1);
        }
    
        private int[] quickSort(int[] arr, int left, int right) {
            if (left < right) {
                int partitionIndex = partition(arr, left, right);
                quickSort(arr, left, partitionIndex - 1);
                quickSort(arr, partitionIndex + 1, right);
            }
            return arr;
        }
    
        private int partition(int[] arr, int left, int right) {
            // 设定基准值(pivot)
            int pivot = left;
            int index = pivot + 1;
            for (int i = index; i <= right; i++) {
                if (arr[i] < arr[pivot]) {
                    swap(arr, i, index);
                    index++;
                }
            }
            swap(arr, pivot, index - 1);
            return index - 1;
        }
    
        private void swap(int[] arr, int i, int j) {
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    
    }
    PHP
    function quickSort($arr)
    {
        if (count($arr) <= 1)
            return $arr;
        $middle = $arr[0];
        $leftArray = array();
        $rightArray = array();
    
        for ($i = 1; $i < count($arr); $i++) {
            if ($arr[$i] > $middle)
                $rightArray[] = $arr[$i];
            else
                $leftArray[] = $arr[$i];
        }
        $leftArray = quickSort($leftArray);
        $leftArray[] = $middle;
    
        $rightArray = quickSort($rightArray);
        return array_merge($leftArray, $rightArray);
    }
    C
    typedef struct _Range {
        int start, end;
    } Range;
    
    Range new_Range(int s, int e) {
        Range r;
        r.start = s;
        r.end = e;
        return r;
    }
    
    void swap(int *x, int *y) {
        int t = *x;
        *x = *y;
        *y = t;
    }
    
    void quick_sort(int arr[], const int len) {
        if (len <= 0)
            return; // 避免len等於負值時引發段錯誤(Segment Fault)
        // r[]模擬列表,p為數量,r[p++]為push,r[--p]為pop且取得元素
        Range r[len];
        int p = 0;
        r[p++] = new_Range(0, len - 1);
        while (p) {
            Range range = r[--p];
            if (range.start >= range.end)
                continue;
            int mid = arr[(range.start + range.end) / 2]; // 選取中間點為基準點
            int left = range.start, right = range.end;
            do {
                while (arr[left] < mid) ++left;   // 檢測基準點左側是否符合要求
                while (arr[right] > mid) --right; //檢測基準點右側是否符合要求
                if (left <= right) {
                    swap(&arr[left], &arr[right]);
                    left++;
                    right--;               // 移動指針以繼續
                }
            } while (left <= right);
            if (range.start < right) r[p++] = new_Range(range.start, right);
            if (range.end > left) r[p++] = new_Range(left, range.end);
        }
    }
    递归法
    void swap(int *x, int *y) {
        int t = *x;
        *x = *y;
        *y = t;
    }
    
    void quick_sort_recursive(int arr[], int start, int end) {
        if (start >= end)
            return;
        int mid = arr[end];
        int left = start, right = end - 1;
        while (left < right) {
            while (arr[left] < mid && left < right)
                left++;
            while (arr[right] >= mid && left < right)
                right--;
            swap(&arr[left], &arr[right]);
        }
        if (arr[left] >= arr[end])
            swap(&arr[left], &arr[end]);
        else
            left++;
        if (left)
            quick_sort_recursive(arr, start, left - 1);
        quick_sort_recursive(arr, left + 1, end);
    }
    
    void quick_sort(int arr[], int len) {
        quick_sort_recursive(arr, 0, len - 1);
    }
    C++
    函数法
    sort(a,a + n);// 排序a[0]-a[n-1]的所有数.
    迭代法
    struct Range {
        int start, end;
        Range(int s = 0, int e = 0) {
            start = s, end = e;
        }
    };
    template <typename T> // 整數或浮點數皆可使用,若要使用物件(class)時必須設定"小於"(<)、"大於"(>)、"不小於"(>=)的運算子功能
    void quick_sort(T arr[], const int len) {
        if (len <= 0)
            return; // 避免len等於負值時宣告堆疊陣列當機
        // r[]模擬堆疊,p為數量,r[p++]為push,r[--p]為pop且取得元素
        Range r[len];
        int p = 0;
        r[p++] = Range(0, len - 1);
        while (p) {
            Range range = r[--p];
            if (range.start >= range.end)
                continue;
            T mid = arr[range.end];
            int left = range.start, right = range.end - 1;
            while (left < right) {
                while (arr[left] < mid && left < right) left++;
                while (arr[right] >= mid && left < right) right--;
                std::swap(arr[left], arr[right]);
            }
            if (arr[left] >= arr[range.end])
                std::swap(arr[left], arr[range.end]);
            else
                left++;
            r[p++] = Range(range.start, left - 1);
            r[p++] = Range(left + 1, range.end);
        }
    }
    递归法
    template <typename T>
    void quick_sort_recursive(T arr[], int start, int end) {
        if (start >= end)
            return;
        T mid = arr[end];
        int left = start, right = end - 1;
        while (left < right) { //在整个范围内搜寻比枢纽元值小或大的元素,然后将左侧元素与右侧元素交换
            while (arr[left] < mid && left < right) //试图在左侧找到一个比枢纽元更大的元素
                left++;
            while (arr[right] >= mid && left < right) //试图在右侧找到一个比枢纽元更小的元素
                right--;
            std::swap(arr[left], arr[right]); //交换元素
        }
        if (arr[left] >= arr[end])
            std::swap(arr[left], arr[end]);
        else
            left++;
        quick_sort_recursive(arr, start, left - 1);
        quick_sort_recursive(arr, left + 1, end);
    }
    template <typename T> //整數或浮點數皆可使用,若要使用物件(class)時必須設定"小於"(<)、"大於"(>)、"不小於"(>=)的運算子功能
    void quick_sort(T arr[], int len) {
        quick_sort_recursive(arr, 0, len - 1);
    }
  • 相关阅读:
    Java进阶10 内存管理与垃圾回收
    C编译: makefile基础
    Java基础09 类数据与类方法
    Java进阶06 容器
    C编译: 动态连接库 (.so文件)
    Java基础10 接口的继承与抽象类
    纸上谈兵: 左倾堆 (leftist heap)
    Java进阶02 异常处理
    Java进阶05 多线程
    Java基础12 类型转换与多态
  • 原文地址:https://www.cnblogs.com/tszr/p/11973779.html
Copyright © 2020-2023  润新知