【算法导论】 堆排序

堆排序算法(Heapsort)

  1. MAX-HEAPIFY过程,其运行时间为О(lg n),是保持最大堆性质的关键
  2. BUILD-MAX-HEAP过程,以线性时间运行,可以在无序的输入数组基础上构造出最大堆
  3. HEAPSORT过程,运行时间О(n lg n),对一个数组原地进行排序

Heapsort过程

1、建最大堆

2、将最大元素A[1] 与 A[i] 交换,堆大小heap-size减一

3、重建堆

4、重复2、3操作,直至堆只剩一个元素

HEAPSORT(A)
    BUILD-MAX-HEAP(A)
    for i <- lenght[A] downto 2
        do exchange(A[1], A[i])
           heap-size[A] <- heapsize[A] - 1
           MAX-HEAPIFY(A, 1)

PARENT(i)
    return ⌊i / 2⌋
LEFT(i)
    return 2i
RIGHT(i)
    return 2i + 1

保持堆性质

MAX-HEAPIFY(A, i)
    l <- LEFT(i)
    r <- RIGHT(i)
    if l <= heap-size[A] and A[l] > A[i]
        then largest <- l
        else  largest <- i
    if r <= heap-size[A] and A[r] > A[largest]
        then largest <- r
    if largest ≠ i
        then exchange A[i] <-> A[largest]
             MAX-HEAPIFY(A, largest)

建堆

对于数组A[1 .. n]

子数组A[ (⌊n/2⌋ + 1) .. n  ]中的元素都是树中的叶子,可看作是只含一个元素的堆。

只需对子数组A[ 1 .. (⌊n / 2⌋) ]做MAX-HEAPIFY操作

BUILD-MAX-HEAP(A)
    heap-size[A] <- length[A]
    for i <- ⌊ length[A] / 2 ⌋ downto 1
        do MAX-HEAPIFY(A, i)


C++实现

#include <iostream>
#include <stdlib.h>
#include <time.h>
int heap_size = 0;

void print(const int *beg, const int *end);
void heapsort(int *ia, size_t size);

void main()
{
	const size_t num = 100000;
	int a[num];
	srand((unsigned) time(NULL));
	for(size_t i = 0; i < num; ++i)
		a[i] = rand() % 10000;
	clock_t start = clock();
	heapsort(a, num);
	clock_t end = clock();
	double time = (double) (end - start) / 1000;
	std::cout << "花费时间" << time << "秒" << std::endl;
	system("pause");
}

/*
	其他函数
*/
void swap(int& i, int& j)
{
	int temp = i;
	i = j;
	j = temp;
}

void print(const int *beg, const int *end)
{
	while(beg != end)
		std::cout << *beg++ << " ";
	std::cout << std::endl;
}

/*
	堆排序所用到的函数
*/



void max_heapify(int *ia, int i)
{
	int w = 2 * i + 1;
	while(w < heap_size)
	{
		if(w + 1 < heap_size)
			if(ia[w + 1] > ia[w])
				++w;
		if(ia[i] > ia[w])
			return;
		swap(ia[i], ia[w]);
		i = w;
		w = 2 * i + 1;
	}
}

void build_max_heap(int *ia, size_t size)
{
	heap_size = size;
	for(int i = size / 2 - 1; i >= 0; --i)
		max_heapify(ia, i);
}

void heapsort(int *ia, size_t size)
{
	build_max_heap(ia, size);
	for(size_t i = size - 1; i >= 1; --i)
	{
		swap(ia[0], ia[i]);
		--heap_size;
		max_heapify(ia, 0);
	}
}

使用STL heap 有关的函数

make_heap(),   pop_heap(),  push_heap(),  sort_heap(),  is_heap; 

is_heap() :
 
原型如下 :
1. bool is_heap(iterator start, iterator end); 
->判断迭代器[start, end] 区间类的元素是否构成一个堆.  是返回true ,否则返回 false.
2. bool is_heap(iterator start, iterator end, StrictWeakOrdering cmp); 
->判断迭代器[start, end] 区间类的元素在cmp条件下是否构成一个堆. 是返回true ,否则返回 false.
  
make_heap() :
 
 原型如下 :
1.void make_heap( random_access_iterator start, random_access_iterator end );
2.void make_heap( random_access_iterator start, random_access_iterator end, StrictWeakOrdering cmp); 
->以 迭代器[start , end] 区间内的元素生成一个堆. 默认使用 元素类型 的 < 操作符 进行判断堆的类型, 因此生成的是大顶堆 .
->当使用了 版本2时, 系统使用 用户定义的 cmp 函数来构建一个堆 
->值得注意的是,  make_heap 改变了 迭代器所指向的 容器 的值.
 
 pop_heap() :
 
 原型如下 :
1. void pop_heap( random_access_iterator start, random_access_iterator end );
2.  void pop_heap( random_access_iterator start, random_access_iterator end, StrictWeakOrdering cmp);
->pop_heap() 并不是真的把最大(最小)的元素从堆中弹出来. 而是重新排序堆. 它把首元素和末元素交换,然后将[first,last-1)的数据再做成一个堆。 
此时, 原来的 首元素 位于迭代器 end-1 的位置,  它已不再属于堆的一员!  
->如果使用了 版本2 , 在交换了 首元素和末元素后 ,使用 cmp 规则 重新构建一个堆.
 
 push_heap() :
 

原型如下 :
1.void push_heap( random_access_iterator start, random_access_iterator end );
2. void push_heap( random_access_iterator start, random_access_iterator end, StrictWeakOrdering cmp); 
-> 算法假设迭代器区间[start, end-1)内的元素已经是一个有效堆, 然后把 end-1 迭代器所指元素加入堆. 
-> 如果使用了 cmp 参数, 将使用 cmp 规则构建堆.
 
sort_heap() : 
 
原型如下 :
1. void sort_heap (random_access_iterator start, random_access_iterator end);
2. void sort_heap (random_access_iterator start, random_access_iterator end, StrictWeakOrdering cmp); 
-> 堆结构被完全破坏, 相当于对元素进行排序, 效果和排序算法类似.  
-> 如果使用了 cmp 参数, 将使用 cmp 规则排序堆. 


#include <iostream>
#include <algorithm>
#include <vector>
#include <stdlib.h>
#include <time.h>
using namespace std;

void print(vector<int>::const_iterator beg, vector<int>::const_iterator end);

void main()
{
	vector<int> ivec;
	const size_t num = 100000000;
	srand((unsigned) time(NULL));
	for(size_t i = 0; i < num; ++i)
		ivec.push_back(rand() % 100000);
	clock_t start = clock();
	make_heap(ivec.begin(), ivec.end());
	sort_heap(ivec.begin(), ivec.end());
	clock_t end = clock();
	double time = (double) (end - start) / 1000;
	cout << time << "秒" << endl;
	system("pause");
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值