zoukankan      html  css  js  c++  java
  • 吴裕雄--天生自然数据结构:十大经典排序算法——快速排序

    快速排序
    快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 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);
    }
  • 相关阅读:
    Atitit fms Strait (海峡) lst 数据列表目录1. 4大洋 12. 著名的海大约40个,总共约55个海 13. 海区列表 23.1. 、波利尼西亚(Polynesia,
    Atitit trave islands list 旅游资源列表岛屿目录1. 东南亚著名的旅游岛屿 21.1. Cjkv 日韩 冲绳 琉球 济州岛 北海道 21.2. 中国 涠洲岛 南澳
    Atitit Major island groups and archipelagos 主要的岛群和群岛目录资料目录1. 岛群 波利尼西亚(Polynesia, 美拉尼西亚(Melanesia,
    Atitit glb 3tie city lst 三线城市列表 数据目录1. 全球范围内约90个城市 三线 12. 世界性三线城市全球共
    Atitit glb 1tie 2tie city lst 一二线城市列表数据约50个一线城市Alpha ++ 阿尔法++,,London 伦敦,,New York 纽约,,Alpha +
    Attit 现代编程语言重要特性目录第一章 类型系统 基本三大类型 2第一节 字符串 数字 bool 2第二节 推断局部变量 2第三节 动态类型 2第二章 可读性与开发效率 简单性 2
    Atitit 未来数据库新特性展望目录1. 统一的翻页 21.1. 2 Easy Top-N
    使用Chrome DevTools(console ande elements panel)进行xpath/css/js定位
    chrome -console妙用之定位xpath/js/css
    表达式树之构建Lambda表达式
  • 原文地址:https://www.cnblogs.com/tszr/p/11973779.html
Copyright © 2011-2022 走看看