这里先介绍简单选择排序,然后在介绍堆排序,(堆排序是选择排序的一种)
选择排序
定义:
选择排序(Selection Sort)是一种简单直观的排序算法。它是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。选择排序是不稳定的排序方法(比如序列【5,5,3】第一次就将第一个【5】与【3】交换,导致第一个5挪到第二个5后面)。
优化:
在选择排序每次遍历数组中,选择最大数与最小数然后在进行交换。
图解:
代码:
void SelectSort(int* a,size_t n) { assert(a); size_t begin = 0; size_t end = n-1; while(begin < end) { size_t min = begin, max = end; for(size_t i=begin; i<=end; i++) { //选最大值、最小值的下标 if(a[i] < a[min]) { min = i; } if(a[i] > a[max]) { max = i; } } //交换 if(max == begin) //(当max==begin时,应进行特殊处理) { max = min; } swap(a[begin],a[min]); swap(a[end],a[max]); ++begin; --end; } }
时间复杂度:O(n^2)
堆排序
定义:
堆排序(HeapSort)是指利用堆这种
数据结构
所设计的一种排序算法,它是选择排序的一种,可以利用数组的快速定位指定索引的元素。
大堆排序的基本思想:
1.先将数据建成一个大堆。
2.再将对顶元素与最后一个元素进行交换,由于交换后新的堆可能违反堆的性质,故应将堆进行调整。
大根堆排序算法的基本操作:
1、建堆 建堆是不断调整堆的过程,从len/2处开始调整,一直到第一个节点。
2.调整堆 利用的思想是比较结点i和它的孩子结点left、right,选出三者最大者,如果最大(小)值不是节点i而是它的一个孩子结点,则交换后会影响这条路径上的其他节点,所以应继续往下调整,直到叶子结点。
3、堆排序:首先是根据元素构建堆,然后将堆的根节点与最后的结点进行交换,将前面len-1个结点继续进行堆调整,在交换根结点。
图解:
升序建大堆小堆问题分析:
时间复杂度:
因为建堆的时间复杂度为O(n),调整堆的时间复杂度是O(lgN),调用了n-1次,所以堆排序的时间复杂度为O(nlgN)
代码:
//堆排序(时间复杂度为O(nlogN)) void AdjustDown(int* a, size_t n, int root) //向下调整算法 { int parent = root; int child = parent*2+1; while(child < n) { if(child+1<n && a[child] < a[child+1]) //当存在左孩子时,进行判断 { ++child; } if(a[child] > a[parent]) { swap(a[parent],a[child]); parent = child; child = parent*2; } else { break; } } } void HeapSort(int *a, size_t n) { assert(a); //建大堆(第一个元素为最大值) for(int i=(n-1-1)/2; i>=0; --i) { AdjustDown(a,n,i); } //排序(将第一个元素与最后一个元素进行交换,再进行向下调整算法) int len = n-1; while(len > 0) { swap(a[0],a[len]); AdjustDown(a,--len,0); /* len--;*/ } }