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

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

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

代码如下:

 /***********************************************************************
* Copyright (C) 2019 Yinheyi. <chinayinheyi@163.com>
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version. * Brief:
* Author: yinheyi
* Email: chinayinheyi@163.com
* Version: 1.0
* Created Time: 2019年05月08日 星期三 21时54分04秒
* Modifed Time: 2019年05月10日 星期五 22时16分17秒
* Blog: http://www.cnblogs.com/yinheyi
* Github: https://github.com/yinheyi
*
***********************************************************************/ // 1. 快速排序是分治思想的又一典型代表,是应用最广的排序算法。
// 2. 分治思想就是把原问题的解分解为两个或多个子问题解,求解出子问题的解之后再构造出原
// 问题的解。
// 3. 在快速排序算法中,它的思想是把一个待排序的数组分成前半部分和后半部分,并且要求
// 前半部分的值都大于等于或都小于等于后半部分的解, 当前半部分与后半部分都变成有序(通
// 过递归调用快速排序来实现)后,我们就不需要合并两个子问题的解就已经得到了原问题的解。
// 这也是为什么要求前半部分都大于等于或都小于等于后半部分的原因。
// 4.所以呢,快速排序的核心在于如何把一个待排序的数组分成两部分!
//
// 核心点:
// 1. 如何把待排序的数组划分为符合要求的两部分!
// 2. 期望的时间复杂度为O(NlogN), 最坏的时间复杂度为O(N*N)
// 3. 快速排序为原址排序,不需要额外的内存空间.
// 4. 快速排序不是稳定排序, 在交换过程中会破坏稳定性。
//
#include<cassert>
#include <stdexcept>
#include <iostream>
static inline void swap(int&, int&);
bool less(int lhs, int rhs);
bool greate(int lhs, int rhs);
static void PrintArray(int array[], int nLength_);
typedef bool (*Compare)(int, int); /**************** 版本一:使用数组的长度作为参数 ***************/
// 该函数实现对数组数列的划分;
// 输入值为数组指针/数组的长度/比较函数指针,
// 返回值为划分点的下标, 也就是后半部分第一个元素的下标;
int Partition(int array[], int nLength_, Compare CompFunc)
{
if (array == nullptr || nLength_ <= || CompFunc == nullptr)
{
assert(false);
throw std::invalid_argument("参数不合法!");
} int _nBoundValue = array[]; // 划分区间的边界值
int _nBoundIndex = ; // 指向边界的下标, 即第二部分第一个元素的下标;
for (int i = ; i < nLength_; ++i)
{
if (CompFunc(array[i], _nBoundValue))
{
swap(array[i], array[_nBoundIndex]);
++_nBoundIndex;
}
} // 如果第一个元素正好是最大或最小元素时,把返回值加1, 也就是把数组划分为第一个元素
// 和剩余的其它元素两部分。
if ( == _nBoundIndex)
return _nBoundIndex + ;
else
return _nBoundIndex;
} // 快速排序的功能函数
void QuickSort(int array[], int nLength_, Compare CompFunc)
{
if (array == nullptr || nLength_ <= || CompFunc == nullptr)
return; int _nPartionIndex = Partition(array, nLength_, CompFunc);
QuickSort(array, _nPartionIndex, CompFunc);
QuickSort(array + _nPartionIndex, nLength_ - _nPartionIndex, CompFunc);
} /**************** 版本二:使用数组的下标区间作为参数 ***************/
// 该函数实现对数组的划分。
// 输入参数为数组指针/半闭半开区间[start, end)表示的数组范围/比较谓词
// 返回值为划分点的下标, 也即后半部分第一个元素的下标。
int Partition_Version2(int array[], int nStart_, int nEnd_, Compare CompFunc)
{
if (array == nullptr || nEnd_ - nStart_ <= || CompFunc == nullptr)
{
assert(false);
throw std::invalid_argument("参数不合法!");
} int _nBoundValue = array[nStart_]; // 划分区间的边界值
int _nBoundIndex = nStart_; // 指向边界的下标, 即第二部分第一个元素的下标;
for (int i = nStart_ + ; i < nEnd_; ++i)
{
if (CompFunc(array[i], _nBoundValue))
{
swap(array[i], array[_nBoundIndex]);
++_nBoundIndex;
}
} // 如果第一个元素正好是最大或最小元素时,把返回值加1, 也就是把数组划分为第一个元素
// 和剩余的其它元素两部分。
if (_nBoundIndex == nStart_)
return _nBoundIndex + ;
else
return _nBoundIndex;
} void QuickSort_Version2(int array[], int nStart_, int nEnd_, Compare CompFunc)
{
if (array == nullptr || nEnd_ - nStart_ <= || CompFunc ==nullptr)
return; int _nPartionIndex = Partition_Version2(array, nStart_, nEnd_, CompFunc);
QuickSort_Version2(array, nStart_, _nPartionIndex, CompFunc);
QuickSort_Version2(array, _nPartionIndex, nEnd_, CompFunc);
} // 测试函数
/*************** main.c *********************/
int main(int argc, char* argv[])
{
int array[] = {-, , , , , -, , , , };
std::cout << "原数组的顺序为:" << std::endl;
PrintArray(array, );
std::cout << "版本一的快速排序:" << std::endl;
std::cout << "从小到大:" << std::endl;
QuickSort(array, , less);
PrintArray(array, );
std::cout << "从大到小:" << std::endl;
QuickSort(array, , greate);
PrintArray(array, );
std::cout << std::endl; int array2[] = {-, , , , , -, , , , };
std::cout << "版本二的快速排序:" << std::endl;
std::cout << "从小到大:" << std::endl;
QuickSort_Version2(array2, , , less);
PrintArray(array2, );
std::cout << "从大到小:" << std::endl;
QuickSort_Version2(array2, , , greate);
PrintArray(array2, ); return ;
} inline void swap(int& lhs, int& rhs)
{
int _nTemp = lhs;
lhs = rhs;
rhs = _nTemp;
} // 小于比较函数
bool less(int lhs, int rhs)
{
return lhs < rhs;
} // 大于比较函数
bool greate(int lhs, int rhs)
{
return lhs > rhs;
} // 打印数组函数
static void PrintArray(int array[], int nLength_)
{
if (nullptr == array || nLength_ <= )
return; for (int i = ; i < nLength_; ++i)
{
std::cout << array[i] << " ";
} std::cout << std::endl;
}

排序算法的c++实现——快速排序的更多相关文章

  1. 排序算法<No.2>【快速排序】

    最近因为项目需要,研究AI相关的东西,主要是算法相关的. 有感触,所以决定,来一个系列的博文,可能会耗时很久,那就是要完成算法系列.起点,从最常用最基本的排序开始.后续会跟进其他类型的,比如树,图等领 ...

  2. 排序算法五:随机化快速排序(Randomized quicksort)

    上一篇提到,快速排序的平均时间复杂度是O(nlgn),比其他相同时间复杂度的堆排序.归并排序都要快,但这是有前提的,就是假定要排序的序列是随机分布的,而不是有序的.实际上,对于已经排好的序列,如果用快 ...

  3. java排序算法之冒泡排序和快速排序

    总结一下Java排序算法,以便记忆. 各类排序的时间复杂度: 排序方法 时间复杂度(平均) 时间复杂度(最坏) 时间复杂度(最好) 空间复杂度 稳定性 复杂性 直接插入排序 O(n2)O(n2) O( ...

  4. 排序算法Java实现(快速排序)

    算法描述:对于一组给定的记录,通过一趟排序后,将原序列分为两部分,其中前一部分的所有记录均比后一部分的所有记录小,然后再依次对前后两部分的记录进行快速排序,递归该过程,直到序列中的所有记录均有序为止. ...

  5. 排序算法C语言实现——快速排序的递归和非递归实现

    /*快排 -  递归实现nlogn*//*原理:    快速排序(Quicksort)是对冒泡排序的一种改进.    快速排序由C. A. R. Hoare在1962年提出.它的基本思想是:通过一趟排 ...

  6. 排序算法Nb三人组-快速排序

    核心思想: 将列表中第一个元素拿出来,放到一边,左右两个循环,左面的大于拿出来的数,就把他挪到右面, 右面的小于拿出来的数就把他放在左面,这是列表被第一个元素''分''为两个列表,在对两个列表进行同样 ...

  7. Java中的排序算法(2)

    Java中的排序算法(2) * 快速排序 * 快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为两个子序列(sub-lists). * 步骤为: * 1. 从数 ...

  8. JavaScript版排序算法

    JavaScript版排序算法:冒泡排序.快速排序.插入排序.希尔排序(小数据时,希尔排序会比快排快哦) //排序算法 window.onload = function(){ var array = ...

  9. 《算法导论》读书笔记之排序算法—Merge Sort 归并排序算法

    自从打ACM以来也算是用归并排序了好久,现在就写一篇博客来介绍一下这个算法吧 :) 图片来自维基百科,显示了完整的归并排序过程.例如数组{38, 27, 43, 3, 9, 82, 10}. 在算法导 ...

随机推荐

  1. MacOS下IDEA设置智能提示不区分大小写

    本文只针对,IDEA-2019.2.3版本 目录地址: Edit -> General -> Code Completion -> Match case -> 勾选去掉 截图如 ...

  2. sqlyog 下载

    https://www.cnblogs.com/givemelove/p/7777975.html

  3. Java 并发系列之五:java 锁

    1. Lock接口 2. 队列同步器AQS 3. 重入锁 ReentrantLock 4. 读写锁 ReentrantReadWriteLock 5. LockSupport工具 6. Conditi ...

  4. 关于微信小程序前端Canvas组件教程

    关于微信小程序前端Canvas组件教程 微信小程序Canvas接口函数 ​ 上述为微信小程序Canvas的内部接口,通过熟练使用Canvas,即可画出较为美观的前端页面.下面是使用微信小程序画图的一些 ...

  5. Lab1:bootloader操作系统的启动

    前言 最近接了一个外包项目再加上填一些之前立的flag,发现好像很久没有发博客了.现在编译原理操作系统算法方面都还有大坑没有填,加上离实习越来越近,应用层方面的学习也要加强了,但反倒是压力越大越想摸鱼 ...

  6. 解决 ImportError: cannot import name 'initializations' from 'keras' (C:\Users\admin\AppData\Roaming\Python\Python37\site-packages\keras\__init__.py)

    解决 ImportError: cannot import name 'initializations' from 'keras' : [原因剖析] 上述代码用的是 Keras version: '1 ...

  7. JOI徽章

    [题目描述] 日本信息学奥赛委员会为了应援将要去台湾参加 IOI 的选手们,打算制作一面新的 JOI 旗帜 .JOI 旗帜为由 M 行 N 列的 M*N 个正方形组 成的图形,每个正方形里写有 J,O ...

  8. SQLServer---------使用Excel 往sqlServer数据库中导入数据

    1.右击创建好的表选择编辑200行 2.保证Excel的字段顺序与数据中顺序一致 3.选中好了后进行复制 4.打开文本   一个快捷方式 将excel 中的数据 黏贴放到文本中 5.点击sql    ...

  9. 不能随便用get和set

    有些对象呢,保存一半.如果你只提供get和set,那么备份不了数据. previousState的get和set还是最新的 wtforms InputRequired: DataRequired: i ...

  10. Jenkins教程(四)安装BlueOcean与Maven构建

    前言 本文旨在使用BlueOcean实现构建可视化与使用Maven构建上一节Jenkins教程(三)添加凭据与流水线拉取Git代码拉下来的代码 什么是Blue Ocean Blue Ocean 重新思 ...