zoukankan      html  css  js  c++  java
  • 排序算法的c++实现——快速排序

        快速排序是分治思想的又一典型代表,是应用最广的排序算法。分治思想就是把原问题的解分解为两个或多个子问题解,求解出子问题的解之后再构造出原问题的解。

        在快速排序算法中,它的思想是把一个待排序的数组分成前半部分和后半部分,并且要求前半部分的值都大于等于或都小于等于后半部分的解, 当前半部分与后半部分都变成有序(通过递归调用快速排序来实现)后,我们就不需要合并两个子问题的解就已经得到了原问题的解。这也是为什么要求前半部分都大于等于或都小于等于后半部分的原因。所以呢,快速排序的核心在于如何把一个待排序的数组分成两部分!


    说明几点:
    1. 如何把待排序的数组划分为符合要求的两部分!
    2. 期望的时间复杂度为O(NlogN), 最坏的时间复杂度为O(N*N)
     3. 快速排序为原址排序,不需要额外的内存空间.
     4. 快速排序不是稳定排序, 在交换过程中会破坏稳定性。

    代码如下:

      1 /***********************************************************************
      2   *   Copyright (C) 2019  Yinheyi. <chinayinheyi@163.com>
      3   *   
      4   * This program is free software; you can redistribute it and/or modify it under the terms
      5   * of the GNU General Public License as published by the Free Software Foundation; either 
      6   * version 2 of the License, or (at your option) any later version.
      7   
      8   *   Brief:    
      9   *   Author: yinheyi
     10   *   Email: chinayinheyi@163.com
     11   *   Version: 1.0
     12   *   Created Time: 2019年05月08日 星期三 21时54分04秒
     13   *   Modifed Time: 2019年05月10日 星期五 22时16分17秒
     14   *   Blog: http://www.cnblogs.com/yinheyi
     15   *   Github: https://github.com/yinheyi
     16   *   
     17   ***********************************************************************/
     18   
     19   
     20   // 1. 快速排序是分治思想的又一典型代表,是应用最广的排序算法。
     21   // 2. 分治思想就是把原问题的解分解为两个或多个子问题解,求解出子问题的解之后再构造出原
     22   // 问题的解。
     23   // 3. 在快速排序算法中,它的思想是把一个待排序的数组分成前半部分和后半部分,并且要求
     24   // 前半部分的值都大于等于或都小于等于后半部分的解, 当前半部分与后半部分都变成有序(通
     25   // 过递归调用快速排序来实现)后,我们就不需要合并两个子问题的解就已经得到了原问题的解。
     26   // 这也是为什么要求前半部分都大于等于或都小于等于后半部分的原因。
     27   // 4.所以呢,快速排序的核心在于如何把一个待排序的数组分成两部分!
     28   //
     29   // 核心点:
     30   // 1. 如何把待排序的数组划分为符合要求的两部分!
     31   // 2. 期望的时间复杂度为O(NlogN), 最坏的时间复杂度为O(N*N)
     32   // 3. 快速排序为原址排序,不需要额外的内存空间.
     33   // 4. 快速排序不是稳定排序, 在交换过程中会破坏稳定性。
     34   //
     35   #include<cassert>
     36   #include <stdexcept>
     37   #include <iostream>
     38   static inline void swap(int&, int&);
     39   bool less(int lhs, int rhs);
     40   bool greate(int lhs, int rhs);
     41   static void PrintArray(int array[], int nLength_);
     42   typedef bool (*Compare)(int, int);
     43   
     44   /****************  版本一:使用数组的长度作为参数        ***************/
     45   // 该函数实现对数组数列的划分;
     46   // 输入值为数组指针/数组的长度/比较函数指针,
     47   // 返回值为划分点的下标, 也就是后半部分第一个元素的下标;
     48   int Partition(int array[], int nLength_, Compare CompFunc)
     49   {
     50       if (array == nullptr || nLength_ <= 0 || CompFunc == nullptr)
     51       { 
     52           assert(false);
     53           throw std::invalid_argument("参数不合法!");
     54       }       
     55   
     56       int _nBoundValue = array[0];        // 划分区间的边界值
     57       int _nBoundIndex = 0;               // 指向边界的下标, 即第二部分第一个元素的下标;
     58       for (int i = 1; i < nLength_; ++i)      
     59       {   
     60           if (CompFunc(array[i], _nBoundValue))
     61           {
     62               swap(array[i], array[_nBoundIndex]);
     63               ++_nBoundIndex;
     64           }       
     65       }  
     66   
     67       // 如果第一个元素正好是最大或最小元素时,把返回值加1, 也就是把数组划分为第一个元素
     68       // 和剩余的其它元素两部分。
     69       if (0 == _nBoundIndex)
     70           return _nBoundIndex + 1;
     71       else
     72           return _nBoundIndex;
     73   }
     74   
     75   // 快速排序的功能函数
     76   void QuickSort(int array[], int nLength_, Compare CompFunc)
     77   {
     78       if (array == nullptr || nLength_ <=1 || CompFunc == nullptr)
     79           return;
     80   
     81       int _nPartionIndex = Partition(array, nLength_, CompFunc);
     82       QuickSort(array, _nPartionIndex, CompFunc);
     83       QuickSort(array + _nPartionIndex, nLength_ - _nPartionIndex, CompFunc);
     84   }
     85   
     86   /****************  版本二:使用数组的下标区间作为参数        ***************/
     87   // 该函数实现对数组的划分。
     88   // 输入参数为数组指针/半闭半开区间[start, end)表示的数组范围/比较谓词
     89   // 返回值为划分点的下标, 也即后半部分第一个元素的下标。
     90   int Partition_Version2(int array[], int nStart_, int nEnd_, Compare CompFunc)
     91   {
     92       if (array == nullptr || nEnd_ - nStart_ <= 0 || CompFunc == nullptr)
     93       {
     94           assert(false);
     95           throw std::invalid_argument("参数不合法!");
     96       }
     97   
     98       int _nBoundValue = array[nStart_];      // 划分区间的边界值
     99       int _nBoundIndex = nStart_;             // 指向边界的下标, 即第二部分第一个元素的下标;
    100       for (int i = nStart_ + 1; i < nEnd_; ++i)
    101       {
    102           if (CompFunc(array[i], _nBoundValue))
    103           {
    104               swap(array[i], array[_nBoundIndex]);
    105               ++_nBoundIndex;
    106           }
    107       }
    108   
    109       // 如果第一个元素正好是最大或最小元素时,把返回值加1, 也就是把数组划分为第一个元素
    110       // 和剩余的其它元素两部分。
    111       if (_nBoundIndex == nStart_)
    112           return _nBoundIndex + 1;
    113       else
    114           return _nBoundIndex;
    115   }
    116   
    117   void QuickSort_Version2(int array[], int nStart_, int nEnd_, Compare CompFunc)
    118   {
    119       if (array == nullptr || nEnd_ - nStart_ <= 1 || CompFunc ==nullptr)
    120           return;
    121   
    122       int _nPartionIndex = Partition_Version2(array, nStart_, nEnd_, CompFunc);
    123       QuickSort_Version2(array, nStart_, _nPartionIndex, CompFunc);
    124       QuickSort_Version2(array, _nPartionIndex, nEnd_, CompFunc);
    125   }
    126   
    127   // 测试函数
    128   /***************    main.c     *********************/
    129   int main(int argc, char* argv[])
    130   {
    131       int array[10] = {-12, 23, 443, 112, 12, -9098, 3432, 0, 0, 0};
    132       std::cout << "原数组的顺序为:" << std::endl;
    133       PrintArray(array, 10);
    134       std::cout << "版本一的快速排序:" << std::endl;
    135       std::cout << "从小到大:" << std::endl;
    136       QuickSort(array, 10, less);
    137       PrintArray(array, 10);
    138       std::cout << "从大到小:" << std::endl;
    139       QuickSort(array, 10, greate);
    140       PrintArray(array, 10);
    141       std::cout << std::endl;
    142   
    143   
    144       int array2[10] = {-12, 23, 443, 112, 12, -9098, 3432, 0, 0, 0};
    145       std::cout << "版本二的快速排序:" << std::endl;
    146       std::cout << "从小到大:" << std::endl;
    147       QuickSort_Version2(array2, 0, 10, less);
    148       PrintArray(array2, 10);
    149       std::cout << "从大到小:" << std::endl;
    150       QuickSort_Version2(array2, 0, 10, greate);
    151       PrintArray(array2, 10);
    152   
    153       return 0;
    154   }
    155   
    156   
    157   inline void swap(int& lhs, int& rhs)
    158   {
    159       int _nTemp = lhs;
    160       lhs = rhs;
    161       rhs = _nTemp;
    162   }
    163   
    164   // 小于比较函数
    165   bool less(int lhs, int rhs)
    166   {
    167       return lhs < rhs;
    168   }
    169   
    170   // 大于比较函数
    171   bool greate(int lhs, int rhs)
    172   {
    173       return lhs > rhs;
    174   }
    175   
    176   // 打印数组函数
    177   static void PrintArray(int array[], int nLength_)
    178   {
    179       if (nullptr == array || nLength_ <= 0)
    180           return;
    181   
    182       for (int i = 0; i < nLength_; ++i)
    183       {
    184           std::cout << array[i] << " ";
    185       }
    186   
    187       std::cout << std::endl;
    188   }
  • 相关阅读:
    选择排序
    冒泡排序
    排序算法
    排序的稳定性
    散列表查找的代码实现
    处理散列冲突的方法
    jQuery 实时监听input
    PhpStorm
    Memcache 学习
    豆瓣第三方登录
  • 原文地址:https://www.cnblogs.com/yinheyi/p/10847079.html
Copyright © 2011-2022 走看看