简单选择排序
算法原理
- 第iii趟,从所有元素中选择关键字最小的元素与A[i]A[i]A[i]交换
- 每趟排序可以确定一个元素的最终位置,通过n−1n-1n−1趟排序后整个序列有序
代码实现
void SelectSort(int A[], int n){
int i, j, min, k;
for(i=1; i<n; i++){
min = i;
for(j=i+1; j<=n; j++)
if(A[j] < A[min])
min = j;
if(min != i){
k = A[i];
A[i] = A[min];
A[min] = k;
}
}
}
举例

性能分析
- 空间效率:只使用常数个辅助单元,空间复杂度为O(1)O(1)O(1)
- 时间效率:最好情况下,不需要交换元素;最坏情况下,交换3(n−1)3(n-1)3(n−1)次。比较的次数是固定的,为n(n−1)2\frac{n(n-1)}{2}2n(n−1)次,时间复杂度为O(n2)O(n^2)O(n2)
- 稳定性:不稳定
堆排序
算法原理
- 堆的定义:n个关键字序列A[1…n]称为堆,当且仅当序列满足
A[i]>=A[2i]且A[i]>=A[2i+1]或(1)A[i]>=A[2i]且A[i]>=A[2i+1]或\tag{1}A[i]>=A[2i]且A[i]>=A[2i+1]或(1)
A[i]<=A[2i]且A[i]<=A[2i+1](1<=i<=⌊n/2⌋)(2)A[i]<=A[2i]且A[i]<=A[2i+1](1<=i<=\lfloor{n/2\rfloor})\tag{2}A[i]<=A[2i]且A[i]<=A[2i+1](1<=i<=⌊n/2⌋)(2) - 可以将堆视为一棵完全二叉树,满足(1)(1)(1)的堆称为大根堆(大顶堆),满足(2)(2)(2)的称为小根堆(小顶堆)
- 算法步骤(以大顶堆为例)
- 将n个元素的序列建成初始堆,输出堆顶元素
- 将堆底元素送入堆顶,从根开始向下调整,使其保持堆的性质,再输出堆顶元素
- 重复2,直到堆中仅剩下一个元素为止
- 堆的调整
- 对第⌊n/2⌋\lfloor n/2 \rfloor⌊n/2⌋个结点为根的子树进行筛选(若根结点的关键字小于左右孩子中关键字较大者,则交换),使子树变成堆
- 向前依次对各个结点(⌊n/2⌋−1∼1\lfloor n/2\rfloor-1\sim 1⌊n/2⌋−1∼1)为根的子树进行筛选,由于交换会破坏下一级的堆,于是继续筛选,构造下一级的堆,直到以该结点为根的子树变成堆为止。
- 重复第2步建堆,直到根结点
代码实现
void HeapAdjust(int A[], int k, int len){
int i;
A[0] = A[k];
for(i=2*k; i<=len; i*=2){
if(i<len && A[i]<A[i+1])
i++;
if(A[0] > A[i])
break;
else{
A[k] = A[i];
k = i;
}
}
A[k] = A[0];
}
void HeapSort(int A[], int len){
int k;
for(int i=len/2; i>0; i--)
HeapAdjust(A, i, len);
for(int i=len; i>1; i--){
k = A[i];
A[i] = A[1];
A[1] = k;
HeapAdjust(A, 1, i-1);
}
}
举例

性能分析
- 空间效率:仅使用了常数个辅助单元,空间复杂度为O(1)O(1)O(1)
- 时间效率:建堆的时间为O(n)O(n)O(n),然后进行n−1n-1n−1次调整,每次调整的时间复杂度为O(h)O(h)O(h),故在最好、最坏、平均情况下,堆排序的时间复杂度为O(nlog2n)O(n\log_2n)O(nlog2n)
- 稳定性:不稳定