总结: Sort 排序算法
排序总结
面试经验
硅谷某前沿小Startup面试时,问到的一个题目就是写一个快速排序算法。进而面试官问到了各种算法的算法复杂度,进而又问了Merge Sort 与 QuickSort 的优劣。
对排序算法的全面理解,体现了计算机学生的功底。
现在来讲Merge Sort 与Quick Sort 是最流行的算法,以下我们来一步一步地分析:
SORT分类
在计算机科学所使用的排序算法通常被分類為:
- 計算的時間複雜度(最差、平均、和最好表現),依據串列(list)的大小(n)。一般而言,好的表現是O(n logn),且壞的表現是O(n2)。對於一個排序理想的表現是O(n)。僅使用一個抽象關鍵比較運算的排序算法總平均上總是至少需要O(n logn)。
- 記憶體使用量(以及其他電腦資源的使用)
- 穩定性:穩定排序算法會讓原本有相等鍵值的紀錄維持相對次序。也就是如果一個排序算法是穩定的,當有兩個相等鍵值的紀錄R和S,且在原本的串列中R出現在S之前,在排序過的串列中R也將會是在S之前。
- 依據排序的方法:插入、交換、選擇、合併等等。
穩定性
當相等的元素是無法分辨的,比如像是整數,穩定性並不是一個問題。然而,假設以下的數對將要以他們的第一個數字來排序。
(4, 1) (3, 1) (3, 7)(5, 6)
在這個狀況下,有可能產生兩種不同的結果,一個是讓相等鍵值的紀錄維持相對的次序,而另外一個則沒有:
(3, 1) (3, 7) (4, 1) (5, 6) (維持次序)(3, 7) (3, 1) (4, 1) (5, 6) (次序被改變)
不穩定排序算法可能會在相等的鍵值中改變紀錄的相對次序,但是穩定排序算法從來不會如此。不穩定排序算法可以被特別地實作為穩定。作這件事情的一個方式是人工擴充鍵值的比較,如此在其他方面相同鍵值的兩個物件間之比較,(比如上面的比较中加入第二个标准:第二个键值的大小)就會被決定使用在原先資料次序中的條目,當作一個同分決賽。然而,要記住這種次序通常牽涉到額外的空間負擔。【1】
穩定的排序
- 冒泡排序(bubble sort)— O(n2)
- 插入排序(insertion sort)—O(n2)
- 桶排序(bucket sort)—O(n);需要O(k)額外空間
- 计数排序(countingsort)—O(n+k);需要O(n+k)額外空間
- 归并排序(merge sort)—O(n logn);需要O(n)額外空間
- 原地归并排序— O(n2)
- 二叉排序树排序(binary tree sort)— O(n logn)期望时间; O(n2)最坏时间;需要O(n)額外空間
不穩定的排序
- 選擇排序(selection sort)—O(n2)
- 堆排序(heap sort)—O(n log n)
- 快速排序(quick sort)—O(n log n)期望時間,O(n2)最壞情況;對於大的、亂數串列一般相信是最快的已知排序
平均时间复杂度
平均时间复杂度由高到低为:
- 冒泡排序O(n2)
- 选择排序O(n2)
- 插入排序O(n2)
- 堆排序O(n log n)
- 归并排序O(n log n)
- 快速排序O(n log n)
说明:虽然完全逆序的情况下,快速排序会降到选择排序的速度,不过从概率角度来说(参考信息学理论,和概率学),不对算法做编程上优化时,快速排序的平均速度比堆排序要快一些。
面试官还会问到同样的nlogn算法,你是会使用快速排序,还是使用Merge Sort.
一般来讲,Quick Sort的速度还是要快一点,而且Merge Sort 还会使用额外的空间。另外就是MergeSort是稳定的排序。而快速排序是不稳定的。
QUICK SORT
Quick Sort 的算法复杂度【4】:
Worst case performanceO(n2)Best case performanceO(n log n) (simple partition)
or O(n) (three-way partition and equal keys)Average case performanceO(n log n)Worst case space complexityO(n) auxiliary (naive)
O(log n) auxiliary (Sedgewick 1978)
Quick Sort 的优势【3】
See Quicksorton wikipedia:
Typically, quicksort is significantly faster in practice thanother Θ(nlogn) algorithms, because its inner loop can beefficiently implemented on most architectures, and in mostreal-world data, it is possible to make design choices whichminimize the probability of requiring quadratic time.
总而言之
1. Quick Sort 更快
2. 而且是就地排序,空间复杂度为O(1),
3. 是递归算法,在不希望使用递归时,Quick Sort 又不是好的选择了。
4. Quick Sort并不是稳定的算法。原先的次序会被打乱。
Merge SORT
Merge Sort 的算法复杂度:【5】
ClassSorting algorithmData structureArrayWorst case performanceO(n log n)Best case performance
O(n log n) typical,
O(n) natural variantAverage case performanceO(n log n)Worst case space complexityO(n) auxiliary
Merge Sort Comparison with other sortalgorithms【2】
Although heapsort has the same time bounds as merge sort, itrequires only Θ(1) auxiliary space instead of merge sort'sΘ(n). On typical modern architectures, efficient quicksort implementations generally outperformmergesort for sorting RAM-based arrays.[citationneeded] On the other hand, merge sort is astable sort and is more efficient at handling slow-to-accesssequential media. Merge sort is often the best choice for sorting alinked list: in this situation it is relativelyeasy to implement a merge sort in such a way that it requires onlyΘ(1) extra space, and the slow random-access performance of alinked list makes some other algorithms (such as quicksort) performpoorly, and others (such as heapsort) completely impossible.
As of Perl 5.8, merge sort is its default sorting algorithm(it was quicksort in previous versions of Perl). In Java, the Arrays.sort()methods use merge sort or a tuned quicksort depending on thedatatypes and for implementation efficiency switch to insertion sort when fewer than seven arrayelements are being sorted.[11]Python uses Timsort,another tuned hybrid of merge sort and insertion sort, that hasbecome the standard sort algorithm in Java SE7,[12]on the Android platform,[13]and in GNU Octave.[14]
1. Merge Sort对于连续的数据结构比较有优势,因为它是顺序地Merge。而QuickSort需要Random读取。所以对于比如磁带这种媒体,Merge Sort拥有优势。
2. Merge Sort 可以不使用递归来实现。
3. 从Java, Perl对排序算法的选择,我们可以看出Merge Sort & QuickSort都相当流行。
代码:
参考CMU久负盛名的 "Data Structures for Application Programmers 08722 "主页君稍加改进行,去掉了难以理解的++和--等。
GitHub代码链接-
QuickSort :
package Algorithms.sort; /*********************************************************
*
* 08-722 Data Structures for Application Programmers
* Lab 5 Comparing MergeSort with QuickSort
*
* A simple QuickSort implementation
*
*********************************************************/ import java.util.*; public class QuickSort {
//private static final int SIZE = 100000;
private static final int SIZE = 10000;
private static Random rand = new Random(); public static void main(String args[]) {
int[] array = new int[SIZE]; for (int i = 0; i < SIZE; i++)
//array[i] = rand.nextInt();
array[i] = i; //int[] array = {3, 4, 6, 1, 7, 8, 6}; // reversely ordered
/*
for(int i=0;i<SIZE; i++) array[i] = SIZE - i;
*/ quickSort(array); // to make sure sorting works.
// add "-ea" vm argument
assert isSorted(array); System.out.println(isSorted(array));
//printArray(array);
} public static void printArray(int[] arr) {
System.out.println();
for(int i: arr) {
System.out.println(i + " ");
}
} public static void quickSort(int[] arr) {
recQuickSort(arr, 0, arr.length - 1);
} private static void recQuickSort(int[] arr, int left, int right) {
// Just the input parameter.
if (arr == null || left >= right) {
return;
} // we just set the right node to be pivot.
int pivPosition = partition(arr, left, right, arr[right]); recQuickSort(arr, left, pivPosition - 1);
recQuickSort(arr, pivPosition + 1, right);
} // partition the array and return the new pivot position.
private static int partition(int[] arr, int left, int right, int pivot) {
// set the pivot.
int l = left - 1 ;
int r = right; /*
example:
let 6 to be the pivot. (1) At the beginning:
3 4 6 1 7 8 6
l r (2) After the first while loop:
3 4 6 1 7 8 6
l r (3) swap them, then continue to move i and j:
3 4 1 6 7 8 6
l r (3) swap them, then continue to move i and j:
3 4 1 6 7 8 6
l pivot
r
(4) swap the left and the pivot.
3 4 1 6 7 8 6
l pivot */ while (true) {
// Find the first element which does not fulfill the rule
// It will not move out of range because the right node is pivot.
// 浣跨敤< 寰堥噸瑕侊紝杩欐牱鍙互閬垮厤l璺戝埌pivot鐨勪綅缃紝灏辨槸right鐨勪綅缃�
//while (l < r && arr[++l] <= pivot);
while (arr[++l] < pivot); // Find the first element which does not fulfill the rule
// Don't need to move r to be left of LEFT.
while (r > l && arr[--r] > pivot); // If r <= l, means that all the elements is in the right place.
if (r <= l) {
break;
} // Swap the first two elements that does not fit the rule.
swap(arr, r, l);
} // The l pointer point to the first element which is bigger than the pivot.
// So we can put the pivot just here. Because put a big or equal one in the last will not change the rule that:
// all the smaller one is in the left and the right one is in the right.
swap(arr, l, right); return l;
} // private helper method to swap two values in an array
private static void swap(int[] arr, int dex1, int dex2) {
int tmp = arr[dex1];
arr[dex1] = arr[dex2];
arr[dex2] = tmp;
} /**********************************************************
* Check if array is sorted. A simple debugging tool
**********************************************************/
private static boolean isSorted(int[] array) {
return isSorted(array, 0, array.length - 1);
} private static boolean isSorted(int[] array, int lo, int hi) {
for (int i = lo + 1; i <= hi; i++)
if (array[i] < array[i - 1])
return false;
return true;
} }
https://github.com/yuzhangcmu/LeetCode_algorithm/blob/master/sort/QuickSort.java
MergeSort:
package Algorithms.sort; /********************************************************
*
* 08-722 Data Structures for Application Programmers
* Lecture 14 Advanced Sorting
*
* Naive version of Merge Sort
*
*********************************************************/
import java.util.Arrays; public class MergeSort { private static final int SIZE = 10000; public static int[] mergeSort(int[] data) {
// parameter valid judge.
if (data == null) {
return null;
} // the base case.
int len = data.length;
if (len <= 1) {
return data;
} // divide into two arrays.
// create left half and right half.
int left[] = new int[len/2];
int right[] = new int[len - len/2]; System.arraycopy(data, 0, left, 0, len/2);
System.arraycopy(data, len/2, right, 0, len - len/2); // call itself to sort left half
left = mergeSort(left);
right = mergeSort(right); return merge(left, right);
} // Precondition: two input arrays are sorted and they are not null.
private static int[] merge(int[] left, int[] right) {
int len = left.length + right.length; int[] ret = new int[len]; int leftPoint = 0;
int rightPoint = 0; int cur = 0;
while (leftPoint < left.length && rightPoint < right.length) {
if (left[leftPoint] < right[rightPoint]) {
ret[cur++] = left[leftPoint++];
} else {
ret[cur++] = right[rightPoint++];
}
} if (leftPoint >= left.length) {
while (rightPoint < right.length) {
ret[cur++] = right[rightPoint++];
}
} else {
while (leftPoint < left.length) {
ret[cur++] = left[leftPoint++];
}
} return ret;
} public static void main(String[] args) {
int[] a = new int[SIZE];
for (int i = 0; i < SIZE; i++)
a[i] = (int) (Math.random() * SIZE); //mergeSort(a); int[] test = { 42, 12, 89, 27, 94, 63, 3, 78 };
System.out.println(Arrays.toString(mergeSort(test))); // test merge method
int[] left = { 12, 42, 63, 89 };
int[] right = { 3, 27, 78, 94 };
System.out.println(Arrays.toString(merge(left, right))); // test merge method
int[] left2 = {};
int[] right2 = { 3, 27, 78, 94 };
System.out.println(Arrays.toString(merge(left2, right2)));
} }
https://github.com/yuzhangcmu/LeetCode_algorithm/blob/master/sort/MergeSort.java
这应该是主页君见过写得最好的Quick Sort 算法了。欢迎各位大神拍砖指教。
后续还会补充其它排序算法的代码,敬请指正。
Bucket sort
相关链接:
http://www.blogjava.net/javacap/archive/2007/12/14/167618.html
http://zh.wikipedia.org/wiki/%e6%a1%b6%e6%8e%92%e5%ba%8f
桶排序 (Bucket sort)或所谓的箱排序,是一个排序算法,工作的原理是将数组分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)。桶排序是鸽巢排序的一种归纳结果。当要被排序的数组内的数值是均匀分配的时候,桶排序使用线性时间(Θ(n))。但桶排序并不是 比较排序,他不受到 O(n log n) 下限的影响。
桶排序以下列程序进行:
- 设置一个定量的数组当作空桶子。
- 寻访序列,并且把项目一个一个放到对应的桶子去。
- 对每个不是空的桶子进行排序。
- 从不是空的桶子里把项目再放回原来的序列中。
package Algorithms.sort; /**
* @author yovn
*
*/
public class BucketSorter {
public void sort(int[] keys,int from,int len,int max)
{
int[] count = new int[max];
int[] tmp = new int[len]; // count the keys.
for (int i = 0; i < len; i++) {
count[keys[from + i]]++;
} // calculate the position.
// BUG 1: i go from 1 not 0.
for (int i = 1; i < max; i++) {
count[i] = count[i] + count[i - 1];
} // back the array.
System.arraycopy(keys, from, tmp, 0, len); // Place the objects into the right position.
for (int i = len - 1; i >= 0; i--) {
keys[--count[tmp[i]]] = tmp[i];
}
}
/**
* @param args
*/
public static void main(String[] args) { int[] a={1,4,8,3,2,9,5,0,7,6,9,10,9,13,14,15,11,12,17,16};
BucketSorter sorter=new BucketSorter();
sorter.sort(a,0,a.length,20);//actually is 18, but 20 will also work for(int i=0;i<a.length;i++)
{
System.out.print(a[i]+",");
} } }
GITHUB:
https://github.com/yuzhangcmu/LeetCode_algorithm/blob/master/sort/BucketSorter.java
【1】http://zh.wikipedia.org/wiki/排序算法
【2】http://en.wikipedia.org/wiki/Merge_sort
【3】http://stackoverflow.com/questions/680541/quick-sort-vs-merge-sort
【4】http://en.wikipedia.org/wiki/Quicksort
【5】http://en.wikipedia.org/wiki/Merge_sort
总结: Sort 排序算法的更多相关文章
- STL源代码分析——STL算法sort排序算法
前言 因为在前文的<STL算法剖析>中,源代码剖析许多,不方便学习,也不方便以后复习.这里把这些算法进行归类,对他们单独的源代码剖析进行解说.本文介绍的STL算法中的sort排序算法,SG ...
- STL中sort排序算法第三个参数_Compare的实现本质
关于C++ STL vector 中的sort排序算法有三种自定义实现,它们本质上都是返回bool类型,提供给sort函数作为第三个参数. 重载运算符 全局的比较函数 函数对象 我认为从实现方式看,重 ...
- php和c++自带的排序算法
PHP的 sort() 排序算法与 C++的 sort() 排序算法均为不稳定的排序算法,也就是说,两个值相同的数经过排序后,两者比较过程中还进行了交换位置,后期开发应主要这个问题
- 经典排序算法 – 插入排序Insertion sort
经典排序算法 – 插入排序Insertion sort 插入排序就是每一步都将一个待排数据按其大小插入到已经排序的数据中的适当位置,直到全部插入完毕. 插入排序方法分直接插入排序和折半插入排序两种, ...
- 排序算法总结(二)归并排序【Merge Sort】
一.归并排序原理(Wikipedia) 归并排序本质是分治思想的应用,并且各层分治递归可以同时进行 1.申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列 2.设定两个指针,最初位置 ...
- 排序算法总结(一)插入排序【Insertion Sort】
最近在忙着找工作,以前看的排序算法都忘记了,悲剧啦T T现在来回顾一下吧. 这边推荐一个算法可视化的网站,非常有用.http://visualgo.net/ 一.插入排序的思想(Wikipedia) ...
- 排序算法-冒泡排序(Bubble Sort)
package com.wangzhu.sort; /** * 冒泡排序算法 * @ClassName: BubbleSort * @Description: TODO * @author wangz ...
- 基础排序算法之快速排序(Quick Sort)
快速排序(Quick Sort)同样是使用了分治法的思想,相比于其他的排序方法,它所用到的空间更少,因为其可以实现原地排序.同时如果随机选取中心枢(pivot),它也是一个随机算法.最重要的是,快速排 ...
- 基础排序算法之并归排序(Merge Sort)
并归排序是学习分治法 (Merge Sort) 的好例子.而且它相对于选择,插入,冒泡排序来说,算法性能有一定提升.我首先会描述要解决的问题,并给出一个并归排序的例子.之后是算法的思路以及给出伪代码. ...
随机推荐
- ios实例开发精品文章推荐(8.13)
提示用户对产品进行评价 http://www.apkbus.com/android-137752-1-1.html设置UILabel和UITextField的Insets http://www.apk ...
- Delphi单元文件引用名称问题
Delphi新版本的单元文件格式变化了,如windows变成了winapi.windows,如果想在单元引用中使用简称,则需要在工程选项中配置: 这样就可以使用全名或简写来引用单元了.
- linux shell 脚本攻略学习9--rename命令详解
rename命令详解: 对文件重命名是常用的操作之一,一般对单个文件的重命名用mv命令,如: amosli@amosli-pc:~/learn/example$ ls abc.txt amosli@a ...
- [转]2016年linux运维人员必会开源运维工具体系
linux运维人员必会开源运维工具体系 说明:不同的技术人员,不同的阶段确定知识边界非常重要,否则,就像马拉车,不知道终点在哪,累死也达不到目标.例如拿8K要学多少,拿15K要学多少.一个新手也许只想 ...
- VC设置视图背景颜色方法
视图的背景一般来说是白色的,在缺省情况下,它和系统定义的颜色COLOR_WINDOW是一致的.设计者一般会希望自己的程序可以让用户轻松地改变窗口背景颜色,或是用漂亮的图片来充填背景.我们可以用Wind ...
- MySQL导入SQL文件过大或连接超时的解决办法/在navcat执行sql卡在0%
set global max_allowed_packet=100 000 000;set global net_buffer_length=100000;SET GLOBAL interactiv ...
- window 10 企业版激活
一. 用管理员权限打开CMD.EXE 接着输入以下命令: slmgr /ipk NPPR9-FWDCX-D2C8J-H872K-2YT43 弹出窗口提示:“成功的安装了产品密钥”. 继续输入以下命令: ...
- Java中类的设计技巧
1) 一定要将数据设计为私有: 不要破坏封装性.有时需要编写一个访问器或更改器方法,但是最好还是保持实例域的私有性.数据的表示形式可能会改变,但他们的使用方式却不会经常发生变化.当数据保持私有时,他 ...
- Linux 性能測试工具
Linux 性能測试工具 linux performance 查看系统配置 查看CPU信息 lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64- ...
- SharePoint 中时间轴 Timeline的实现
客户需要在OA中实现每日动态功能,能够记录每一位员工的每天的工作动态,我很快想到了时间轴,因为时间轴能很直观的现实员工每一刻的动态.就像Facebook的Timeline效果(点击查看). 尝试着搜索 ...