开始重新拾回我的算法思维之--快速排序

毕业到现在也差不多一年了,之前在校搞ACM时候的痛苦经历已经不在,踏入工作到现在,算法思维逐渐的丢失,工作中遇到的问题也涉及暂时涉及不到算法,记得最后一次用到算法也就是毕设时候了,当时用unity3d写了一个rpg游戏,寻路算法采用的是A*。现在吗....能想起A*的原理已经不错了,所以打算今天开始从新拾回我的算法思维,先从快速排序开始吧,排序也算是最基础的算法了,工作中也是经常使用到(用库函数的就不说了);

先来说说快速排序的原理吧,

设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。

一趟快速排序的算法是:

1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;

2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];

3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]和A[i]互换;

4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换;

5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。

我自己经常吧快排称之为左右挖坑填坑算法......额,好吧,黄色那部分内容呢,是百度上的,其中有我认为不准确的地方,如第3)4)最后的互换两字我觉得用的不恰当,或者说错误。应该改为将A[j]的值赋值给A[i],而此时我们并不需要理会A[j],也就是a[j]将是作为下一个“坑”,“左右挖坑填坑”就是这么来的。为什么这么说呢,且看我用一个来分析。

(以升序为例,倒叙也就是改下符号而已)假设有一个待排序的数组[35,5,42,78,13,29],那么它的第一趟执行完之后是怎样得呢?

好了,理论分析部分完成了,下面一步一步分析代码实现快排的过程。

假设代码只执行了第一步和第二部,代码:

 1 public static void quickSort(int[] arr, int left, int right) {
 2             int key = arr[left];
 3             int i = left;
 4             int j = right;
 5             while (i < j && arr[j] >= key) { //从右向左找比key小的值
 6                 j--;
 7             }
 8             arr[i] = arr[j];//arr[j]比key小,填入第一个坑
 9             while (i < j && arr[i] <= key) { //从左向右找比key大的值
10                 i++;
11             }
12             arr[j] = arr[i];//arr[i]>key ,填入上一个坑
13         }

如果要将一整轮都走完,代码:

 1 public static void quickSort(int[] arr, int left, int right) {
 2             int key = arr[left];
 3             int i = left;
 4             int j = right;
 5             while (i < j) {//如果i不等于j,那么就继续左右挖坑填坑
 6                 while (i < j && arr[j] >= key) { //从右向左找比key小的值
 7                     j--;
 8                 }
 9                 arr[i] = arr[j];//arr[j]比key小,填入第一个坑
10                 while (i < j && arr[i] <= key) { //从左向右找比key大的值
11                     i++;
12                 }
13                 arr[j] = arr[i];//arr[i]>key ,填入上一个坑
14             }
15             arr[i] = key;//当i==j,将key的值填入这一轮比较的最后一个坑中
16         }

接下来就简单了,快排整个函数完成 代码:

 1 public static void quickSort(int[] arr, int left, int right) {
 2             if (left < right) {//终止递归的条件。
 3                 int key = arr[left];
 4                 int i = left;
 5                 int j = right;
 6                 while (i < j) {//如果i不等于j,那么就继续左右挖坑填坑
 7                     while (i < j && arr[j] >= key) { //从右向左找比key小的值
 8                         j--;
 9                     }
10                     arr[i] = arr[j];//arr[j]比key小,填入第一个坑
11                     while (i < j && arr[i] <= key) { //从左向右找比key大的值
12                         i++;
13                     }
14                     arr[j] = arr[i];//arr[i]>key ,填入上一个坑
15                 }
16                 arr[i] = key;//当i==j,将key的值填入这一轮比较的最后一个坑中
17                 quickSort(arr, left, i - 1);//左边部分执行一轮步骤
18                 quickSort(arr, i + 1, right);//右边部分执行一轮步骤
19             }
20         }

快排完成,其中值得注意的是:有些人会将 第7行 arr[j]>=key 条件和第11行 arr[i]<=key条件写成 arr[j]>keyarr[i]<key 。表面上看好像也是正确的,但当有两个数字一样的时候,

 6      while (i < j) {//如果i不等于j,那么就继续左右挖坑填坑
 7                     while (i < j && arr[j] >= key) { //从右向左找比key小的值
 8                         j--;
 9                     }
10                     arr[i] = arr[j];//arr[j]比key小,填入第一个坑
11                     while (i < j && arr[i] <= key) { //从左向右找比key大的值
12                         i++;
13                     }
14                     arr[j] = arr[i];//arr[i]>key ,填入上一个坑
15          }

这段代码会出现死循环,至于为什么会死循环,请将我上面的步骤一步一步推演,即可得知。
时间: 2024-10-19 02:10:31

开始重新拾回我的算法思维之--快速排序的相关文章

Manacher&#39;s algorithm: 最长回文子串算法

Manacher 算法是时间.空间复杂度都为 O(n) 的解决 Longest palindromic substring(最长回文子串)的算法.回文串是中心对称的串,比如 'abcba'.'abccba'.那么最长回文子串顾名思义,就是求一个序列中的子串中,最长的回文串.本文最后用 Python 实现算法,为了方便理解,文中出现的数学式也采用 py 的记法. 在 leetcode 上用时间复杂度 O(n**2).空间复杂度 O(1) 的算法做完这道题之后,搜了一下发现有 O(n) 的算法.可惜

最大回文字符串算法详解与优化

背景 最近开始研究算法,于是在leetcode上做算法题,第五题Longest Palindromic Substring便是关于回文子串的. 什么是回文字串 回文字符串是指将该字符串前后颠倒之后和该字符串一样的字符串.例如:a,aaaa,aba,abba- 最长回文子串 要求最长回文子串,就需要遍历每一个子串,时间复杂度是O(N2):判断字串是不是回文,时间复杂度是O(N),这样的话算法的时间复杂度就是O(N3). 我刚开始想到的就是中心扩展法,代码如下: public static Stri

hdu 3068 Manacher算法 O(n)回文子串算法

题目:http://acm.hdu.edu.cn/showproblem.php?pid=3068 关于算法的教程  推荐这个:http://blog.csdn.net/ggggiqnypgjg/article/details/6645824    注意:我推荐的这篇博客里说的那个代码有bug,我觉得没问题,而是博主在用的时候写错了,博主举得反例我都过了 而且hdu 3068也过了 最开始是用的后缀数组,2000ms+ 果断超时............... 看过一遍很快就学会这个算法了:然后A

hihoCoder #1032 : 最长回文子串 [ Manacher算法--O(n)回文子串算法 ]

传送门 #1032 : 最长回文子串 时间限制:1000ms 单点时限:1000ms 内存限制:64MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进. 这一天,他们遇到了一连串的字符串,于是小Hi就向小Ho提出了那个经典的问题:“小Ho,你能不能分别在这些字符串中找到它们每一个的最长回文子串呢?” 小Ho奇怪的问道:“什么叫做最长回文子串呢?” 小Hi回答道:“一个字符串中连续的一段就是这个字符串的子串,而回文串

玩转算法面试 从真题到思维全面提升算法思维

第1章 算法面试到底是什么鬼?一提起算法面试,很多同学就会心有余悸.可其实,大多数企业的算法面试,并没有那么可怕.并不是一定要啃完整本<算法导论>,才能玩儿转算法面试:也并不是只有ACM参赛选手,才能笑傲算法面试.恰恰相反,大多数算法面试关注的算法思维,其实很基础.在这一章,和大家聊一聊,算法面试,到底是什么鬼?... 第2章 面试中的复杂度分析很多同学一提起复杂度分析就头疼,马上想起了<算法导论>中复杂的数学推导.但其实在一般的企业面试中,对复杂度的分析要求并没有那么高,但也是绕

常用算法之排序算法三【快速排序】

快速排序是东尼·霍尔在1962提出的划分交换排序,并采用一种分治的策略.在这,我们先总结一下:快速排序 = 划分交换排序 + 分治.然后我们在一一介绍他. 划分交换排序 在讨论它时,感觉有种看了崔颢<黄鹤楼>之后,再去写黄鹤楼的感觉,因为MoreWindows写 得白话经典算法系列之六 快速排序 快速搞定已经足够出色了.我在这只是进行简单的复述,你需要了解更多请看他的博文. 先来看看划分交换排序的具体算法描述: 1.从数列中选出一个数作为基准 2.从数组中选出比它大的数放右边,比它小的数放左边

基础算法之排序--快速排序

1 /************************************************************************************** 2 * Function : 快速排序 3 * Create Date : 2014/04/21 4 * Author : NTSK13 5 * Email : [email protected] 6 * Copyright : 欢迎大家和我一起交流学习,转载请保持源文件的完整性. 7 * 任何单位和个人不经本人允许不

算法——基础篇——快速排序

快速排序是一个经常使用的算法,由于每次用的时候,都感觉没有理解清楚,特写一篇文章记录一下. 算法介绍 快速排序有点类似有冒泡排序,冒泡排序从相邻的两个元素比较,小的在左边,大的在右边,这个算法很容易理解.而快速排序它相当于是在一头一尾两边分别排序比较,比较的对象是当前元素值,和一个选定的key值,主题的思想就是通过跟key值比较,把大于key的值放在右边,小于的放在左边这样就完成了一次排序,接着在对key值左边的序列进行同样的操作,右边也是,最后便能将所有的元素给排好序,由于它每次排序,都会分成

iOS算法(一)置快速排序算法

快速排序是当遇到较大数据时,排序快,高效的方法(公司面试时,基本上会被问到...) 该方法的基本思想是: 1.先从数列中取出一个数作为基准数. 2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边. 3.再对左右区间重复第二步,直到各区间只有一个数. 简单地理解就是,找一个基准数(待排序的任意数,一般都是选定首元素),把比小于等于基准数的元素放到基准数的左边,把大于基准数的元素放在基准数的右边.排完之后,在把基准数的左边和右边各看成一个整体, 左边:继续选择基准数把小于等