1、前言:选择排序
void Selection_Sort(ElementType A[], int N)
{
for (i = 0; i < N; i++)
{
MinPosition = ScanForMin(A, i, N–1);
//从A[i]到A[N–1]中找最小元,并将其位置赋给MinPosition
Swap(A[i], A[MinPosition]);
//将未排序部分的最小元换到有序部分的最后位置
}
}
无论如何: T = θ(N2)
问题:如何快速找到最小元???
2、堆排序
在堆排序中,元素下标从0开始。则对于下标为i的元素,其左、右孩子的下标分别为:2i+1, 2i+2
算法1
void Heap_Sort(ElementType A[], int N)
{
BuildHeap(A); //O(N)
for (i = 0; i<N; i++)
TmpA[i] = DeleteMin(A); //O(logN)
for (i = 0; i<N; i++) //O(N)
A[i] = TmpA[i];
}
时间复杂度:T(N) = O(N log N)
缺点:需要额外O(N)空间,并且复制元素需要时间。
算法2
把元素组织成一个大顶锥,取出最大元素与最后一个元素交换,再将最后一个元素移除大顶锥,剩下的元素再组织成大顶锥,取最大值与锥最后一个元素交换,如此重复。
void Heap_Sort(ElementType A[], int N)
{
for (i = N / 2 - 1; i >= 0; i--)//BuildHeap
PercDown(A, i, N);
for (i = N - 1; i>0; i--)
{
Swap(&A[0], &A[i]); //DeleteMax
PercDown(A, 0, i);
}
}
- 定理:堆排序处理N个不同元素的随机排列的平均比较次数是
2N logN - O(Nlog logN) 。 - 虽然堆排序给出最佳平均时间复杂度,但实际效果不如用Sedgewick增量序列的希尔排序。
完整c++代码
#include<iostream>
using namespace std;
typedef int ElementType;
//A存放堆的数组,P要调整的根节点位置,N,整个堆的大小
void PercDown(ElementType*A,int P,int N)//P 为下标,从 0 开始,N:整个堆的大小,3 个元素就是 3
{
int parent, child;
ElementType tmp = A[P];//保存根节点的值
for (parent = P; (parent * 2 + 1) < N; parent = child)//根节点为P,从P开始向下
{//父节点的左孩子为parent*2+1
child = parent * 2 + 1;
if (child != N - 1 && A[child + 1] > A[child])
child++; //Child指向左右子结点的较大者
if (tmp > A[child]) //找到了合适位置
break;
else //下滤
A[parent] = A[child];
}
A[parent] = tmp;
}
void Heap_Sort(ElementType *A, int N)
{
for (int i = N/2-1; i >= 0; i--)//最后一个节点的父节点为N/2-1
PercDown(A,i,N);
for (int i = N - 1; i > 0; i--)
{
swap(A[0],A[i]);
PercDown(A,0,i);
}
}
int main()
{
int a[] = { 4, 6, 1, 8, 9, 3, 7, 0 };
int len = sizeof(a) / sizeof(a[0]);
Heap_Sort(a, len);
for (int i = 0; i < len; i++)
cout << a[i] << " ";
cout << endl;
}