关于快速排序的描述,网上有很多的资料, 我这里引用wiki上的解释来说明一下:
快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为两个子序列(sub-lists)。
步骤为:
从数列中挑出一个元素,称为 "基准"(pivot),
重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分割之后,该基准是它的最后位置。这个称为分割(partition)操作。
递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
递回的最底部情形,
是数列的大小是零或一,也就是永远都已经被排序好了。
虽然一直递回下去,但是这个算法总会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
而学习这个算法的时候,我发现网上有很多资料,但是唯独很少有图解的部分,对于我这样的算法新手来说,理解起来要费点劲。 OK, 现在我把我自己学习这个算法的一些东西,做个图解发上来, 希望能减少新手的学习成本,能对算法的执行过程有个直观的认识,那样的话,就会提高不少效率。(本人学习的时候,效率比较低。)
我们以java语言为例, wiki上有相关的示例:
package com.bbs;
import java.util.Comparator;
import java.util.Random;
/**
* 快速排序使用分治法(Divide and conquer)策略
* 来把一个序列(list)
* 分为两个子序列(sub-lists)。
步骤为:
1.从数列中挑出一个元素,称为 "基准"(pivot),
2.重新排序数列,
所有元素比基准值小的摆放在基准前面,
所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。
在这个分割之后,该基准是它的最后位置。这个称为分割(partition)操作。
3.递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
* @author google
*/
public class QuickSort {
public static void main(String[] args) {
int[] intt={5,7,9,3,14};
qsort(intt,0,intt.length-1);
for (Integer i:intt) {
System.out.println(i);
}
}
public static final Random RND=new Random();
/**
* 交换指定元素
* @param ary
* @param i
* @param j
*/
public static void swap(int[] ary,int i,int j){
int tmp=ary[i];
ary[i]=ary[j];
ary[j]=tmp;
}
/**
* 获取枢纽元素
* @param ary
* @param begin
* @param end
* @param cmp
* @return
*/
private static int partition(int[] ary,int begin,int end){
//随即定位枢纽的位置
int index=begin+RND.nextInt(end-begin+1);
// int index=0;
//获取枢纽的值
int pivot=ary[index];
//获取枢纽后, 将其置放到数组的最后一个位置
swap(ary,index,end);
//之后循环数组, 与曲扭进行比较, 相当于重新排数组
for(int i=index=begin;i<end;i++){
//如果当前元素小于枢纽,则交换位置
if(ary[i]<pivot){
swap(ary, index++, i);
}
}
swap(ary, index, end);
return index;
}
/**
* 执行快速排序的方法
* @param ary
* @param begin
* @param end
* @param cmp
*/
public static void qsort(int[] ary,int begin,int end){
if(end>begin){
//找到枢纽
int index=partition(ary, begin, end);
qsort(ary, begin, index-1);
qsort(ary, index+1, end);
}
}
public static void sort(int[] ary){
qsort(ary, 0,ary.length-1);
}
}
下面,我以一个上述main方法中的调用为例,来把每一步算法执行过程图解一下。 当然,这个算法最核心的部分就是查找枢纽的方法。 也就是
/**
* 获取枢纽元素
* @param ary
* @param begin
* @param end
* @param cmp
* @return
*/
private static int partition(int[] ary,int begin,int end){
//随即定位枢纽的位置
int index=begin+RND.nextInt(end-begin+1);
// int index=0;
//获取枢纽的值
int pivot=ary[index];
//获取枢纽后, 将其置放到数组的最后一个位置
swap(ary,index,end);
//之后循环数组, 与曲扭进行比较, 相当于重新排数组
for(int i=index=begin;i<end;i++){
//如果当前元素小于枢纽,则交换位置
if(ary[i]<pivot){
swap(ary, index++, i);
}
}
swap(ary, index, end);
return index;
}
OK, 开始。 我们输入数组
int[] intt={5,4,7,10,3};
调用qsort方法, 其首先会要去查找枢纽位置。
public static void qsort(int[] ary,int begin,int end){
if(end>begin){
//找到枢纽
int index=partition(ary, begin, end);
qsort(ary, begin, index-1);
qsort(ary, index+1, end);
}
}
直接进入这个方法。
private static int partition(int[] ary,int begin,int end){
//随即定位枢纽的位置 这里假设index为 0 既以第一个元素 5 为枢纽值
int index=begin+RND.nextInt(end-begin+1);
//获取枢纽的值
int pivot=ary[index];
//获取枢纽后, 将其置放到数组的最后一个位置
swap(ary,index,end);
//之后循环数组, 与曲扭进行比较, 相当于重新排数组
for(int i=index=begin;i<end;i++){
//如果当前元素小于枢纽,则交换位置
if(ary[i]<pivot){
swap(ary, index++, i);
}
}
swap(ary, index, end);
return index;
}
那数组的初始图为:
在获取枢纽值后,我们将枢纽值与最后一元素交换, 则存储图为:
ok, 现在我们要做的事情就是要重排数组
既:
2.重新排序数列,
所有元素比基准值小的摆放在基准前面,
所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。
在这个分割之后,该基准是它的最后位置。这个称为分割(partition)操作。
(代码中体现在for循环中, for(int i=index=begin;i<end;i++)
当然,这里有个值得注意的地方, index=begin. index由原来指向枢纽的位置,被重新定位到了数组的开始位置
则进行for循环的次数为end, 这里我们要注意的是 end的实际参数值为 数组的.length-1. 这里既是4
每次循环中,数组的变化如下图, 注意, 小于枢纽5的只有 数组的第4个元素 3哦, 执行到这里,程序会有变化,注意看图:
第一次循环
第2次循环
第3次循环:
第4次循环(3<5): 交换小于枢纽的值到数组的第一位,同时index也++操作。
可以理解为记录小于枢纽的数的数量,同时也是下一个小于枢纽数的存储位置。
(如果还有小于枢纽值的话,就把它存放到ary[index++]位置上,既ary[1]上。)
最后,在for循环结束后, 需要将枢纽数放到数组的分界处,并返回枢纽的位置。return index.
(个人这样理解,因为之前说过,index代表着所有小于枢纽数数量,也是下一个小于枢纽数的位置。
那么当数组中再没有小于枢纽数的时候, index就标识枢纽值自己本身应该去的地方, 如图中的
3,5,9,14,7 这里index就是1。那么index左边的都是小于枢纽的数.)
OK,这样,快速排序就把第一次的枢纽位置找到了,然后,将数组按枢纽位置划分为2部分。
既 所有小于枢纽值的部分 ary[begin,index-1]
所有大于枢纽值的部分 ary[index+1,end]
再利用递归,分别对两部分进行再一次的quicksort.
最后,将所有的部分合并起来,就可以得到一个最后有序的数组了。
最后发一张快速排序执行的动态图, 你也可以从WIKI上找得到。
这里就快速排序的执行做了一个简单的介绍,希望对刚学快排的朋友有帮助,由于自身水平的有限,所以文章水平也很有限,希望各位拍拍砖。
- 大小: 3.7 KB
- 大小: 3.9 KB
- 大小: 8.6 KB
- 大小: 8.2 KB
- 大小: 8.5 KB
- 大小: 21.6 KB
- 大小: 18.5 KB
- 大小: 130 KB
分享到:
相关推荐
本资源"数据结构与算法分析--C语言描述"是针对数据结构初学者的一个优秀教材,旨在帮助读者快速掌握这一领域。 首先,数据结构是组织和存储数据的方式,它决定了数据的访问效率和处理速度。常见的数据结构包括数组...
《数据结构与算法分析_C++语言描述(第2版)》是Larry Nyhoff撰写的一本经典教材,专注于探讨数据结构和算法的理论及其在C++编程语言中的实现。这本书不仅适合初学者,也对有一定经验的程序员有很高的参考价值。在...
《数据结构与算法分析-C语言描述》是一本深入探讨数据结构和算法的书籍,它以C语言为载体,为读者提供了丰富的编程实践。这本教材的编程练习是学习过程中的重要组成部分,旨在帮助读者巩固理论知识,提升实际编程...
### 数据结构与算法分析 #### 书目简介与特点 《数据结构与算法分析》是一本专注于使用Java语言介绍数据结构和算法的经典教材。作者Robert Lafore以轻松幽默的方式介绍了如何利用数据结构解决实际问题,这使得本书...
《数据结构与算法分析---C语言描述》这本书详细的介绍了算法的基本原理和实现方法,书中使用伪代码的形式阐述了各种数据结构的特色和算法的运行机制。这本书是用C语言来描述算法的,因为C语言在IT行业内有着非常重要...
《数据结构与算法分析-c语言描述》是一本专注于数据结构和算法分析的学术书籍,以其深入浅出的方式和严谨的逻辑深受学术界和IT行业人士的欢迎。本书利用C语言作为编程工具来介绍和分析各种数据结构和算法,使得读者...
### 数据结构与算法分析-C++描述 #### 一、引言 《数据结构与算法分析-C++描述》这本书是计算机科学领域中非常重要的教材之一,它深入浅出地讲解了数据结构的基本概念以及各种算法的设计与分析方法。本书第三版在前...
数据结构与算法分析是计算机科学中的核心领域,它关乎如何高效地存储和处理信息,以及设计解决问题的方法。在这个主题中,C语言常被选为实现这些概念的编程语言,因为它的效率高、接近硬件,适合底层操作。"数据结构...
数据结构与算法分析是计算机科学中的核心领域,它关乎如何高效地存储和处理数据,以及设计和实现解决问题的计算过程。Allen Weiss所著的《数据结构与算法分析》系列书籍,以其深入浅出的讲解和丰富的实例,成为了该...
数据结构与算法分析是计算机科学中的核心课程,它关乎如何高效地存储和处理数据,以及设计和实现高效的算法。在Java语言环境下,这门课程更显得尤为重要,因为Java以其跨平台特性和强大的类库支持,成为了许多开发者...
数据结构与算法分析是计算机科学中的核心领域,它关乎如何高效地存储和处理数据,以及设计和实现高效的算法。在C语言中学习数据结构与算法分析,能够让你深入理解底层机制,这对于提升编程技能和优化代码性能至关...
《数据结构与算法分析-C语言描述》是一本深入解析数据结构和算法的权威书籍,它以其清晰的C语言实现和深刻的算法分析而受到广大程序员和计算机科学学生的喜爱。该书覆盖了众多重要的数据结构,如数组、链表、栈、...
### 数据结构与算法分析——C++语言描述 #### 标题解析 - **标题内容**:“数据结构与算法分析c++语言描述” - **解析**:该标题表明本书主要介绍了数据结构与算法的相关知识,并使用C++编程语言来进行具体实现与...
《数据结构与算法分析——C++语言描述》是一本经典的计算机科学教材,主要针对程序员和计算机科学专业的学生,深入探讨了如何使用C++语言来实现和分析数据结构和算法。这本书由Mark Allen Weiss撰写,是程序设计领域...
数据结构和算法分析是计算机科学的核心领域,C++作为一种强大且通用的编程语言,常用于实现这些概念。《数据结构和算法分析-C++描述代码》第三版是一本经典的教材,它深入浅出地介绍了各种数据结构和算法,并提供了...
以下是基于标题“数据结构与算法-java”及描述中提到的“数据结构与算法分析_Java语言描述高清版(第2版)1.pdf”所涵盖的一些关键知识点: 1. **数据结构**: - **数组**:最基础的数据结构,存储固定大小的同类型...
《数据结构与算法分析——C语言描述》是计算机科学领域的一本经典著作,由Mark Allen Weiss撰写,英文版第三版由人民邮电出版社出版。这本书深入浅出地讲解了数据结构和算法的基础知识,是学习计算机科学的重要参考...