【排序问题】
输入:一个n个数的序列<a1, a2, ..., an>。
输出:输入序列的一个排列(重排)<a1', a2', ..., an'>,使得a1' <= a2' <= ... an'。
输入序列通常是一个n元数组,尽管它可以用链表等其他方式描述。
【为什么要排序】
很多计算机科学家认为 排序是算法研究中最基础的问题。
【插入排序】
由于其内层循环非常紧凑,对于 小规模输入,插入排序是一种非常快的原址排序算法。
如果输入数组中仅有常数个元素需要在排序过程中存储在数组之外,则成排序算法是原址的(in place)。
【空间原址性】任何时候都只需要常数个额外的元素空间存储临时数据。
【比较排序算法】
插入排序、归并排序、快速排序、堆排序等都是比较排序算法——
通过对元素进行比较操作 来确定输入数组的有序次序。
比较排序算法的排序n个元素的最坏情况运行时间的下界为Ω(nlgn)。
【线性时间排序】
采用比较操作之外的方法来获得输入序列有序次序的信息,以打破Ω(nlgn)的下界,以获得线性时间O(n)。
计数排序:O(n+k),数值集合为{0, 1, ..., k};当k=O(n)时,可以获得线性运行时间。
基数排序:O(d(n+k)),每个整数有d位,每个数字可能取k值;当d是常数且k=O(n)时,其运行时间为线性的。
桶排序:O(n),当n个实数在半开区间[0, 1)内服从均匀分布的n个实数,桶排序的平均情况运行时间为O(n)。
【顺序统计量】
一个n个数的集合的 第i个顺序统计量就是集合中第i小的数。
当不知道其顺序,先排序再输出第i个元素的方式,运行时间为Ω(nlgn)。
****************************************************
【堆】
A[1...n],树的根结点为为A[1],这样容易计算得到父节点、左孩子、右孩子。
在堆排序的好的实现中,下面这三个函数通常是以宏或者内联函数的方式实现的:
#define PARENT( i ) ( i >> 1 )
#define LEFT( i ) ( i << 1 )
#define RIGHT( i ) ( i << 1 + 1)
【最大堆】A[PARENT( i )] >= A[i]
【最小堆】A[PARENT( i )] <= A[i]
最大堆性质:
(1)堆中最大元素在根结点中;且任一子树中,该子树包含的所有结点的值都不大于该子树根结点的值。
(2)含n个元素的堆的高度为lgn下取整。
(3)当用数组存储n个结点时,最后一个非叶节点为[n/2」 = PARENT( n )。
#if 1
#include <iostream>
using namespace std;
#define PARENT( i ) ( i >> 1 )
#define LEFT( i ) ( i << 1 )
#define RIGHT( i ) ( i << 1 + 1)
//(1)MAX-HEAPIFY过程:其时间复杂度为O(lgn),它是维护最大堆性质的关键。
template<typename T>
void max_heapify( T a[], int i, int heap_size )
{// 可以将heap_size集成到包含T a[]的堆类中
int c;
T data;
data = a[i];
c = LEFT( i );
while( c <= heap_size ){
if( c < heap_size && a[c] < a[c+1] )
++c;
if( data >= a[c] )
break;
a[PARENT(c)] =a[c];// 自己编程遗忘了这一步
c = LEFT( c );
}
a[PARENT(c)] = data;
}
//(2)BUILD-MAX-HEAP过程:具有线性时间复杂度;O(nlgn)-->O(n)
// 功能是从无序的输入数据数组中构造一个最大堆。
template<typename T>
void build_max_heap( T a[], int heap_size )
{
if( a == NULL || heap_size <= 1 )
return;
for( int i = PARENT( heap_size ); i >= 1; --i ){
max_heapify( a, i, heap_size );
}
}
//(3)HEAPSORT过程:其时间复杂度为O(nlgn),功能是对一个数组进行原址排序
template<typename T>
void heap_sort( T a[], int heap_size )
{
build_max_heap( a, heap_size );
for( int i = heap_size; i >= 2; --i ){
#if defined( TEST )
for( int j = 1; j <= heap_size; ++j )
cout << a[j] << " ";
cout << endl;
#endif
T tmp = a[1];
a[1] = a[i];
a[i] = tmp;
max_heapify( a, 1, i - 1 );
//max_heapify( a, i, heap_size );
}
}
//(4)MAX-HEAP-INSERT
template<typename T>
void max_heap_insert( T a[], int heap_size, int max_size, T& data )
{
if( heap_size == max_size )
return;// throw out_of_bounds("NoMem");
int c = ++heap_size;
while( c != 1 && a[PARENT(c)] < a[c] ){
a[c] = a[PARENT(c)];
c = PARENT(c);
}
a[c] = data;
}
int main( void )
{
int a[] = { 0, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7 };
heap_sort<int>( a, sizeof(a) / sizeof(int) - 1 );
for( int i = 1; i < sizeof( a ) / sizeof( int ); ++i )
cout << a[i] << " ";
cout << endl;
}
#endif