快速排序是在面试中经常问到的算法题,也比较难掌握,特别是没有经常写算法的人儿。记得在大学的时候,我真的没有真正地理解快速排序,主要是那个时候对递归的理解不深,然后再加上对算法的理解能力不够强,导致当年百度二面被刷了。
下面就让笔者来带大家回忆回忆大学那些年到底是怎么学的~
用笔者所理解的话来说,其算法思想是利用分而治之的思想,每一趟都保证左边比基准小,右边比基准大,而且递归划分排序。
一趟快速排序的算法是:
举个例子:
上面留下来了一个问题为什么一定要j指针先动呢?首先这也不是绝对的,这取决于基准数的位置,因为在最后两个指针相遇的时候,要交换基准数到相遇的位置。一般选取第一个数作为基准数,那么就是在左边,所以最后相遇的数要和基准数交换,那么相遇的数一定要比基准数小。所以j指针先移动才能先找到比基准数小的数。
快速排序是不稳定的,其时间平均时间复杂度是O ( nlgn )。
void quickSort(int a[], int len, int left, int right) { // 所有都排序完毕了,就退出递归 if left >= right { return; } // 每一趟划分,使左边的比基准小,右边的比基准大,并返回新的基准的位置 int baseIndex = partition(a, len, left, right); // 递归排序左部分 quickSort(a, len, left, baseIndex - 1); // 递归排序右部分 quickSort(a, len, baseIndex + 1, right) } int partition(int a[], int len, int left, int right) { // 记录哪个是基准数 int base = a[left]; // 记录当前基准数的位置 int baseIndex = left; while left < right { // 先从右边往左边扫描,找到第一个比base还要小的数,但是不能与left相遇 while left < right && a[right] >= base { right--; } // 再从左边往右边扫描,找到第一个比base还要大的数,但是不能与right相遇 while left < right && a[left] <= base { left++; } // 将所扫描到的第一个比基准数小和第一个比基准数大的数交换 swap(a, left, right); } // 交换left与baseIndex对应的元素,将left位置的元素作为新的基准数 swap(a, baseIndex, left); // 返回新的基准位置 return left; } void swap(int a[], int i, int j) { int temp = a[i]; a[i] = a[j]; a[j] = temp; }
void quickSort(int a[], int len, int left, int right) { if (left >= right) { return; } // 一次划分后,得到基准数据的位置 int baseIndex = partition(a, len, left, right); // 快排左边部分 quickSort(a, len, left, baseIndex - 1); // 快排右边部分 quickSort(a, len, baseIndex + 1, right); } int partition(int a[], int len, int left, int right) { // 每一次的划分,都让第一个元素作为基准 int base = a[left]; // 记下刚开始的基准的位置, 便于最后相遇时交换 int baseIndex = left; while (left < right) { // 查找右部分比base还小的元素的下标 while (left < right && a[right] >= base) { right--; } // 查找左部分比base还大的元素的下标 while (left < right && a[left] <= base) { left++; } // 将这一趟比基准大和比基准小的所找到的第一个值,互相交换 swap(a, left, right); } // 在left与right相遇时,将基准数与相遇点交换 // 这样这一次划分,就可以保证左边的比基准数小,右边的比基准数大 swap(a, baseIndex, left); // 划分完成后,以left位置的元素作为新的基准,分成左右序列,分别递归排序 return left; } void swap(int a[], int i, int j) { int temp = a[i]; a[i] = a[j]; a[j] = temp; }
funcquickSort(inouta: [Int],left: Int,right: Int) { if left >= right { return } letbaseIndex = partition(&a,left: left,right: right) quickSort(&a,left: left,right: baseIndex - 1) quickSort(&a,left: baseIndex + 1,right: right) } funcpartition(inouta: [Int], varleft: Int, varright: Int) ->Int { letbase = a[left] let baseIndex = left while left < right { while left < right && a[right] >= base { right-- } while left < right && a[left] <= base { left++ } swapInt(&a,i: left,j: right) } swapInt(&a,i: baseIndex,j: left) return left } funcswapInt(inouta: [Int],i: Int,j: Int) { lettemp = a[i] a[i] = a[j] a[j] = temp }
如果还是不懂,那么再重头看一遍,并认真地去理一理思路吧!相信一定会领悟的~
关注 | 账号 | 备注 |
---|---|---|
标哥博客iOS交流群一 | 324400294(满) | 群一若已满,请申请群二 |
标哥博客iOS交流群二 | 494669518(满) | 群二若已满,请申请群三 |
标哥博客iOS交流群三 | 461252383(满) | 群三若已满,请申请群四 |
标哥博客iOS交流群四 | 250351140 | 群四若已满,会有提示信息 |
关注微信公众号 | iOSDevShares | 关注微信公众号,会定期地推送好文章 |
关注新浪微博账号 | 标哥的技术博客 | 关注微博,每次发布文章都会分享到新浪微博 |
关注标哥的GitHub | CoderJackyHuang | 这里有很多的Demo和开源组件 |
关于我 | 进一步了解标哥 | 如果觉得文章对您很有帮助,可捐助我! |