排序算法的c++实现——快速排序

Posted yinheyi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序算法的c++实现——快速排序相关的知识,希望对你有一定的参考价值。

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

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


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

代码如下:

  1 /***********************************************************************
  2   *   Copyright (C) 2019  Yinheyi. <[email protected]>
  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: [email protected]
 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   }

 

以上是关于排序算法的c++实现——快速排序的主要内容,如果未能解决你的问题,请参考以下文章

快速排序-递归实现

在最佳情况下,由于堆栈溢出错误,快速排序算法失败 - C++

内部排序算法总结(上)C++实现

排序算法 | 快速排序(含C++/Python代码实现)

算法笔记 排序算法完整介绍及C++代码实现 HERODING的算法之路

排序算法的c++实现——快速排序