1.普遍认为:
当N很小时,快速排序慢,归并排序快
当N很大时,并且有序程度高时,快速排序最快
当N很大时,并且有序程序低时,堆排序最快
当N很小时,快速排序慢,归并排序快
当N很大时,并且有序程度高时,快速排序最快
当N很大时,并且有序程序低时,堆排序最快
快速排序是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短;
堆排序所需的辅助空间少于快速排序,并且不会出现快速排序可能出现的最坏情况。这两种排序都是不稳定的。
若要求排序稳定,则可选用归并排序。先利用直接插入排序求得较长的有序子文件,然后再两两归并之。因为直接插入排序是稳定的,所以改进后的归并排序仍是稳定的。
堆排序所需的辅助空间少于快速排序,并且不会出现快速排序可能出现的最坏情况。这两种排序都是不稳定的。
若要求排序稳定,则可选用归并排序。先利用直接插入排序求得较长的有序子文件,然后再两两归并之。因为直接插入排序是稳定的,所以改进后的归并排序仍是稳定的。
但是:由于快速排序不稳定,因此数据量极大时不如选用堆排序。
2. 堆排序占花费是时间主要是在建堆的时候。
所以在数据量方面来说,如果数据量越大,堆排序的优势就越明显。
所以在数据量方面来说,如果数据量越大,堆排序的优势就越明显。
大多数商用软件都采用快排,因为它在一般情况下是排序最快的算法。
然而,快排绝不能用于需要特定响应时间的系统,除非这个系统能承受O(n^2)的时间复杂度。
如果你预先估计可能会碰到这种最坏情况,那么
如果n比较小,改用插入排序——由于代码简单,它的时间复杂度的常数项比较少
如果n比较大,改用堆排序——你应该用堆排序,因为它能保证O(nlogn)的时间复杂度.
然而,快排绝不能用于需要特定响应时间的系统,除非这个系统能承受O(n^2)的时间复杂度。
如果你预先估计可能会碰到这种最坏情况,那么
如果n比较小,改用插入排序——由于代码简单,它的时间复杂度的常数项比较少
如果n比较大,改用堆排序——你应该用堆排序,因为它能保证O(nlogn)的时间复杂度.
//堆排序
- void BuildMaxHeap(int *,int );
- void MaxHeapify(int *,int,int);
- void heap_sort(int *,int ,int );
- void swap(int *a, int m,int n)
- {
- int temp=a[m];
- a[m]=a[n];
- a[n]=temp;
- }
//测试堆排序
- for( i=0; i<size; i++)
- {
- array0[i]=array_b[i];
- }
- i=heap_sort(array0,0,size-1);
- cout<<"Heap Sort Running Time:"<<i<<endl;
- fout<<"Heap Sort Running Time:"<<i<<endl;
- void heap_sort(int *a,int start,int end)
- {
- int i;
- int length=end-start;
- int hsize=length;
- BuildMaxHeap(a,hsize);
- for( i=length; i>1; i--)
- {
- swap(a,1,i);
- hsize--;
- MaxHeapify(a,1,hsize);
- }
- }
- void BuildMaxHeap(int *a,int size)
- {
- int i;
- for( i=size/2; i>0; i--)
- {
- MaxHeapify(a,i,size);
- }
- }
- void MaxHeapify(int *a,int i,int size)
- {
- int l,r,largest;
- l=2*i;
- r=2*i+1;
- if(l<=size &&a[l]>a[i])
- largest=l;
- else
- largest=i;
- if(r<=size && a[r]>a[largest])
- largest=r;
- if(largest!= i)
- {
- swap(a,i,largest);
- MaxHeapify(a,largest,size);
- }
- }
3.同时也指明了快速排序递归调用次数太多时会出现栈溢出,并给出了非递归版的快速排序法。
//快速排序
//测试快速排序
- int partition(int *, int ,int );
- void quick_sort(int *, int ,int);
- void quick_sort_rec(int *, int ,int);
//测试快速排序
- for( i=0; i<size; i++)
- {
- array0[i]=array_b[i];
- }
- i=run_sort(quick_sort_rec,array0,0,size-1);
- cout<<"Quick Sort Running Time:"<<i<<endl;
- fout<<"Quick Sort Running Time:"<<i<<endl;
- int partition(int *a,int low,int high)
- {
- int i,j;
- int key=a[high];
- i=low-1;
- j=low;
- for( ; j<high; j++)
- {
- if(a[j]<=key)
- {
- i++;
- swap(a,i,j);
- }
- }
- swap(a,i+1,high);
- return i+1;
- }
- void quick_sort_rec(int *a,int low,int high)
- {
- int mid;
- if(low<high)
- {
- mid=partition(a,low,high);
- quick_sort_rec(a,low,mid-1);
- quick_sort_rec(a,mid+1,high);
- }
- }
//非递归版 --迭代
- void quick_sort(int *base,int start,int end)
- {
- const int stacksize=1000;
- int *stack=new int[stacksize];
- int top=0;
- stack[top++]=start;
- stack[top++]=end-start+1;
- while(top!=0)
- {
- //cout<<top<<endl;
- top--;
- int r=stack[top];
- top--;
- int p=stack[top];
- if(p>=r)
- continue;
- int m=partition(base,p,r);
- //push the left
- stack[top++]=p;
- stack[top++]=m-1;
- //push the right
- stack[top++]=m+1;
- stack[top++]=r; }}
附上阿里面试题:
问题一:若有1T的数据,比如 只有两列,身份证号和姓名 需要实现由大到小排序,你用什么办法,能否做到 复杂度为O(n),说说你的思路和想法?
问题二:有10个G的数据,也是一样,比如两列,身份证号和姓名,如果两条数据一样,则表示该两条数据重复了,现在给你512的内存,把这10G中重复次数最高的10条数据取出来。
参考思路:
用身份证号的前三位切割这个数据,这样会分成999份,
每一份再进行排序,比如构造一个平衡二叉树,最典型的的就是TreeMap和TreeSet(TreeSet底层是使用了TreeMap算法,而TreeMap算法底层是实现了红黑树的平衡二叉树的排序);
然后按照文件名进行排序,这样就实现了大数据排序;
因为排序二叉树的复杂度为O(lgn)到O(n) ;
因此我们可以做到 O(n)
问题二:
解法是一样的 按照身份证号前三位 分割999份,然后对这每个文件找到重复的最多的十条,这样,我们得到了999个文件,每个文件有 10条数据
在对这个999*10条进行排序找到 重复率最高的十条即可;