MIT:算法导论——4.1.排序和顺序统计量_堆排序

【排序问题】
输入:一个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









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值