比较排序之堆排序和快速排序
2016-09-17 22:24
211 查看
堆排序
堆是一个数组,它可以被看成一个近似的完全二叉树,树上的每一个结点对应数组中的一个元素。除了最底层外,改树是完全充满的,而且是从左往右填充的。 堆可以分成两种形式:最大堆和最小堆。 在堆排序算法中,我们使用的是最大堆。最小堆一般用于构建优先队列。 我们知道,在最大堆中,最大堆性质是指除了根以外的所有结点i都要满足: A[parent(i)]>=A[i] 也就是说,某个结点的值至多与其父节点一样大,因此,堆中最大的元素存放在根结点中。 所有我们需要一个用于维护最大堆性质的函数。它的输入是一个数组A和一个下标i,我们维护最大堆性质函数的作用就是让以下标i为根结点的堆遵循最大堆性质。
void max_heap(int *a,int i,int n) //n=a.length { int j=i*2+1; //i's child node int temp=a[i]; while(j<n) { if(a[j]<a[j+1]&&j+1<n) j++; if(a[i]>=a[j]) break; a[i]=a[j]; i=j; j=i*2+1; } a[i]=temp; }
现在我们就可以将我们要排序的数据建成一个最大堆数组。
void build_max_heap(int *a,int n) { for(int i=n/2-1;i>=0;i--) max_heap(a,i,n); }
现在我们拥有了建立最大堆的能力,那么我们就可以用它来排序,因为最大的元素就在根结点处,所以我们将根结点放入数组的最后,然后将剩下的元素再建成一个最大堆,再将根结点放入数组的最后,依次循环,我们就排好序了。
void heap_sort(int *a,int n) { for(int i=n-1;i>=0;i--) { build_max_heap(a,i+1); swap(a[0],a[i]); } }
我们可以看出堆排序的时间复杂度跟归并排序相同是O(nlgn),但是它的空间复杂度与插入排序相同都是常数。
快速排序
快速排序也使用了分治思想,它的原理是找一个主元,然后将数组里的每一个元素与主元相比较,比主元小的放在主元左边,比主元大的放在主元右边,然后以主元为界,对左右两个子数组进行相同的操作,依次下去,就可以排好序了。 下面我们以数组最后一个元素为主元:
int partition(int *a,int i,int n) { int key=a ; int m=i-1; for(int j=i;j<n;j++) { if(a[j]<=key) { m+=1; swap(a[m],a[j]); } } swap(a[m+1],a ); return m+1; } void quick_sort(int *a,int i,int n) { int q; if(i<n) { q=partition(a,i,n); quick_sort(a,i,q-1); quick_sort(a,q+1,n); } }
我们可以看到快排的最坏情况时间复杂度是O(n^2),而在元素互异的情况下,期望时间复杂度是O(nlgn)。
相关文章推荐
- 堆排序、快速排序(递归与非递归)、归并排序效率比较
- 冒泡排序,选择排序,插入排序,堆排序,归并排序,快速排序
- 冒泡排序,选择排序,插入排序,快速排序的比较及优化
- 算法有插入排序,堆排序,合并排序,快速排序和stooge排序
- 冒泡排序、插入排序、选择排序、希尔排序、堆排序、归并排序等常用排序算法的比较
- 排序(希尔排序,堆排序,归并排序,快速排序)
- 算法导论之插入排序,选择排序,归并排序,冒泡排序,希尔排序,堆排序,快速排序的c语言实现
- 选择排序和快速排序性能比较
- 老生常谈比较排序之堆排序
- 快速排序、归并排序、堆排序三种算法性能比较
- 插入排序、归并排序、冒泡排序和快速排序性能比较
- 堆排序与快速排序效率比较
- 快速排序和堆排序的使用场景比较
- 对c语言系统库函数、堆排序、希尔排序、折半插入排序、快速排序消耗时间的比较
- 排序总结JS版(冒泡排序、简单选择排序、快速插入排序、希尔排序、堆排序、快速排序)
- 归并排序,堆排序,基数排序,希尔排序,快速排序,交换排序,选择排序和插入排序的总结和比较
- 冒泡排序,快速排序,堆排序比较
- 【更新】排序算法比较:插入排序,冒泡排序,归并排序,堆排序,快速排序,计数排序,基数排序,桶排序
- 排序(快速排序和堆排序)练习
- 冒泡排序,快速排序,堆排序比较