排序算法学习(快速排序)

1.介绍

     快速排序是由东尼·霍尔所发展的一种排序算法。

     在平均状况下,排序 n 个项目要 Ο(nlogn) 次比较。

     在最坏状况下则需要 Ο(n2) 次比较,但这种状况并不常见。

     事实上,快速排序通常明显比其他 Ο(nlogn) 算法更快,

     因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。

      快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。

      快速排序又是一种分而治之思想在排序算法上的典型应用。

      本质上来看,快速排序应该算是在冒泡排序基础上的递归分治法。

      快速排序的名字起的是简单粗暴,因为一听到这个名字你就知道它存在的意义,

       就是快,而且效率高!它是处理大数据最快的排序算法之一了。

       虽然 Worst Case 的时间复杂度达到了 O(n²),但是人家就是优秀,

       在大多数情况下都比平均时间复杂度为 O(n logn) 的排序算法表现要更好, 可是这是为什么呢,我也不知道。

        解答:在《算法艺术与信息学竞赛》的答案:

            快速排序的最坏运行情况是 O(n²),比如说顺序数列的快排。

            但它的平摊期望时间是 O(nlogn),且 O(nlogn) 记号中隐含的常数因子很小,

             比复杂度稳定等于 O(nlogn) 的归并排序要小很多。

             所以,对绝大多数顺序性较弱的随机数列而言,快速排序总是优于归并排序。

 

2.步骤

  第一步:从数列中挑出一个元素,称为 "基准"(pivot);

  第二步:重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面

              ( 相同的数可以到任一边)。

                在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;

   第三步:递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;

 

3.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;
  }

 

4.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]

   

 5.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]
  }         

  

6.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);
     }
  }

 

7.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;
     }

  
}

   总结:partition方法就是分区,以pivot下标元素为基准,将小的元素放到左边,大的放到右边

              swap方法是数组元素相互替换

              quickSort就是不停的递归,直到left和right都相同位置,说明递归分治结束了

 

学习来源:https://www.runoob.com/w3cnote/quick-sort-2.html

posted @ 2020-09-03 16:44  小窝蜗  阅读(218)  评论(0编辑  收藏  举报