C#递归算法之快速排序
作者:Robin 发布时间:2021-08-16 21:13:37
上两片第归算法学习:
1)递归算法之分而治之策略
2)递归算法之归并排序
上一篇学习中介绍了了递归算法在排序中的一个应用:归并排序,在排序算法中还有一种算法用到了递归,那就是快速排序,快速排序也是一种利用了分而治之策略的算法,它由C.A.R发明,它依据中心元素的值,利用一系列递归调用将数据表划分成越来越小的子表。在每一步调用中,经过多次的交换,最终为中心元素找到最终的位置。与归并算法不同,快速排序是就地排序,而归并排序需要把元素在临时向量中拷贝,下面通过对以下向量进行排序来理解和加深快速排序算法的步骤:
v={800,150,300,650,550,500,400,350,450,400,900};
利用快速排序算法对此数据表进行排序的第0级划分过程如下: 向量v的索引范围为:[first,last) = [0,10),则中心点的索引为mid = (0+10)/2=5,中心点的值为v[5] = 500
快速排序算法的第一次划分的目的就是将向量v依据v[5]的值划分成两个子表subList1和subList2,其中subList1中的值都小于v[5],而subList2中的值都大于v[5],我们将subList1称为左子表,subList2称为右子表,并且确定v[5]的最终位置
下面就是实现这一目的需要我们作出的工作步骤:
1)首先将中心元素与起始位置的元素进行交换。
2)分别扫描左子表和右子表,左子表扫描起始位置为 first+1, 右子表从last-1开始。左子表从左向右扫描扫描,右子表从右向左扫描。直到左子表扫描位置大于或者等于右子表扫描位置时候结束。
在第一个步骤中,得到如下的数据表
500 150 300 650 550 800 400 350 450 400
而此时的左子表扫描位置处于索引1处,右子表扫描位置处于索引9处,先从左子表扫描,直到找到数据值大于中间值500的位置停止扫描,然后扫描右子表,直到找到数据值小于中间值500并且右子表的扫描位置(scanDown)要小于左子表开始位置,防止数据溢出。找到之后,交换左子表与右子表中中扫描位置的元素,图示如下:
在交换v[3](650>500)与v[8](450<500)后,继续扫描左子表和右子表,如图
直到满足条件scanUp>=scanDown,然后scanDown所在位置就是中心元素500的最终位置,交换v[0]与v[scanDown)=v[5],第一次划分级别的最终结果数据集为:400,150,300,450,350,500,800,550,650,900,此时得到的左子表为:400,150,300,450,350,右子表为:800,550,650,900
下一个划分级别是处理上一级别产生的子表,按照相同的处理方法分别处理左子表和右子表,左子表索引位置[0,5),右子表索引位置[6,10),按照上面的处理步骤处理左子表(400,150,300,450,350)得到的最终结果为:150,300,400,450,350 右子表最终处理结果为:550,650,800,900 在处理结果中300与650分别是中心值,他们现在的位置就是最终位置
在接下来的处理中,总是处理上一步骤中留下的子表,当子表数目<=1的时候就不用处理子表了,而子表有两个元素的时候,比较大小,然后交换两元素位置即可。
大于2个元素的子表都和上面的处理步骤一样,我们将上面的处理过程编写出一个函数
private int PivotIndex(int[] v, int first, int last),那么快速排序算法就是对此函数的递归调用
/// <summary>
/// 交换位置
/// </summary>
/// <param name="v"></param>
/// <param name="index1"></param>
/// <param name="index2"></param>
private void Swrap(int[] v, int index1, int index2)
{
int temp = v[index1];
v[index1] = v[index2];
v[index2] = temp;
}
/// <summary>
/// 将向量V中索引{first,last)划分成两个左子表和右子表
/// </summary>
/// <param name="v">向量V</param>
/// <param name="first">开始位置</param>
/// <param name="last">结束位置</param>
private int PivotIndex(int[] v, int first, int last)
{
if (last == first)
{
return last;
}
if (last - first == 1)
{
return first;
}
int mid = (first + last) / 2;
int midVal = v[mid];
//交换v[first]和v[mid]
Swrap(v, first, mid);
int scanA = first + 1;
int scanB = last - 1;
for (; ; )
{
while (scanA <= scanB && v[scanA] < midVal)
{
scanA++;
}
while (scanB > first && midVal <= v[scanB])
{
scanB--;
}
if (scanA >= scanB)
{
break;
}
Swrap(v, scanA, scanB);
scanA++;
scanB--;
}
Swrap(v, first, scanB);
return scanB;
}
public void Sort(int[] v, int first, int last)
{
if (last - first <= 1)
{
return;
}
if (last - first == 2)
{
//有两个元素的子表
if (v[first] > v[last - 1])
{
Swrap(v, first, last - 1);
}
return;
}
else
{
int pivotIndex = PivotIndex(v, first, last);
Sort(v, first, pivotIndex);
Sort(v, pivotIndex + 1, last);
}
}
快速排序因为每次划分都能将中心值元素找到最终的位置,并且左边值都小于中心值,右边都大于中心值,它的时间复杂度平均和归并算法一致为O(nlog2n);
任何一种基于比较的排序算法的时间复杂度不可能小于这个数,除非不使用比较的方法进行排序。
算法程序:http://xiazai.jb51.net/201606/yuanma/QuickSort(jb51.net).rar


猜你喜欢
- Java类的加载说明Java类的编译代码都存在于它自己的独立文件中(class),该文件只在需要使用程序代码时才会被加载。类加载在创建类的第
- 本文实例为大家分享了Android实现多条目加载展示的具体代码,供大家参考,具体内容如下展示效果依赖testCompile 'jun
- 本文实例为大家分享了Android实现房贷计算器的具体代码,供大家参考,具体内容如下fangdai(activity)package com
- 参数校验主要使用两个标签@Validated和@Valid;@Valid是Hibernate的注解校验,@Validated是spring的
- 本文就是会将数组里面的单词进行倒序排列 例如 how old are you -> you are old how示例程序输出结果:t
- SpringBoot2之PUT请求接收不了参数的解决办法,这个问题,关乎两个Filter过滤器,是spring3和3.5之后提供的,目的就是
- Java-关键字:final1 .final可以用来修饰的结构:类、方法、变量2.final 用来修饰一个类:此类不能被其他类所继承比如:S
- 前言:在我们使用C# WinForm中,我们有时候是需要或者自己本机的IP地址进行处理,今天我们学习一下如何使用C# Winform获取主机
- 本文实例为大家分享了java实现省市区转换成树形结构的具体代码,供大家参考,具体内容如下前言:为什我想写这篇博客呢?第一方面是记录,另一方面
- producer是生产者的意思:指生产数据的线程,consumer是消费者的意思:指的是使用数据的线程public class Produc
- 本文介绍在C#窗体编程时,如何设置不显示右上角的最小化最大化关闭按钮。可以通过this.ControlBox这个属性的值来控制。在Windo
- 本文实例讲述了Java Bean与xml互相转换的方法。分享给大家供大家参考,具体如下:XML和Java Bean互相转换是一个很有用的功能
- 本文实例为大家分享了Android实现屏幕保持常亮的具体代码,供大家参考,具体内容如下一、需求背景当我们在玩游戏或者看视频的时候不希望app
- 本文实例讲述了Java实现指定线程执行顺序的三种方式。分享给大家供大家参考,具体如下:方法一:通过共享对象锁加上可见变量来实现。public
- 宏定义与预处理命令预处理阶段:处理宏定义与预处理命令;编译期:检查代码,分析语法、语义等,最后生成.o或.obj文件;链接期:链接所有的.o
- 本文实例为大家分享了java生成字母验证码的具体代码,供大家参考,具体内容如下import java.awt.BasicStroke;imp
- 有序链表:按关键值排序。删除链头时,就删除最小(/最大)的值,插入时,搜索插入的位置。插入时需要比较O(N),平均O(N/2),删除最小(/
- 目录常用APIgeoaddgeoposgeodistgeoradiusbymembergeohash在外卖软件中的附近的美食店铺、外卖小哥的
- 本文采用C#实例讲解了处理图片为浮雕效果的实现方法,这在PS中是一个常见的功能,也是C#中的一个简单的图像处理例子。程序先读取原图,然后依次
- 1.搜索树的概念二叉搜索树是一种特殊的二叉树,又称二叉查找树,二叉排序树,它有几个特点:如果左子树存在,则左子树每个结点的值均小于根结点的值