您的位置:首页 > 其它

学习算法导论——堆排序

2016-03-01 11:31 405 查看
《算法导论》第三版书中数组下标是从1开始的,但是这里从0开始。

1.堆定义

堆分为两种,即最大堆和最小堆,最大堆的定义为:当数组A大小为n时(A中有n个元素),若2*i+1<n有A[i]>=A[2*i+1];若2*i+2<n有A[i]>=A[2*i+2],则这样的数据结构称为最大堆。说白了就是根节点(包括子树的根节点)的值不小于左节点和右节点的值(如果有左或右节点的话)。
最小堆和最大堆刚好相反。

2.创建最大堆

这里以最大堆为例。
首先要了解的一些知识是对于根节点i,其左孩子节点为2*i+1,右孩子节点为2*i+2;第一个非叶节点为(n-2)/2;其中n为数组大小。

unsigned Left_Child(unsigned i)
{
return 2 * i + 1;
}

unsigned Right_Child(unsigned i)
{
return 2 * i + 2;
}


下面的Max_Heapily()函数是使得根节点为i的树(子树)为最大堆
void Max_Heapily(unsigned A[], unsigned i,unsigned n)//维持根节点为i的树为最大堆
{
unsigned l = Left_Child(i);
unsigned r = Right_Child(i);
unsigned largest=i;

if (l < n && A[l] > A[largest])
largest = l;

if (r < n && A[r]>A[largest])
largest = r;

if (largest != i)
{
unsigned temp = A[i];
A[i] = A[largest];
A[largest] = temp;
Max_Heapily(A, largest,n);//递归调整子树
}
}
void Build_Max_Heap(unsigned A[], unsigned n)//从第一个非叶节点到根节点调整为最大堆
{
for (int i = (n - 2) / 2; i >= 0; --i)
{
Max_Heapily(A, i, n);
}
}
上面的Build_Max_Heap()函数为什么从第一个非叶节点开始循环?因为根据最大堆的定义,不但整课树为最大堆,所有的子树也为最大堆,第一个非叶节点就是第一颗子树的根节点。存在疑问的地方是,那直接Max_Heapily(A,0,n)不就行了吗?不行,该函数调整的是根节点和左右孩子节点:



只有上面图片中的是三个节点不符合最大堆时,它才会调整子树。

3.堆排序算法

首先,把有n个元素的数组A初始化创建为最大堆,然后循环执行如下过程直到数组为空为止:(1)把堆顶A[0]元素(为最大元素)和当前最大堆的最后一个元素交换;(2)最大堆元素个数减1;(3)由于第(1)步后根节点不再满足最大堆的定义,所以调整根节点使之满足最大堆的定义。
void Heap_Sort(unsigned A[],unsigned n)
{
Build_Max_Heap(A,n);
for (unsigned i = n - 1; i > 0; --i)
{
unsigned temp = A[0];
A[0] = A[i];
A[i] = temp;
Max_Heapily(A, 0, --n);
}
}


int main(int argc, char* argv[])
{
unsigned A[10] = {4,1,3,2,16,9,10,14,8,7};

Heap_Sort(A, 10);
for (unsigned i = 0; i < 10; ++i)
{
std::cout << A[i] << " ";
}
getchar();
return 0;
}


结果:





另一种创建最大堆的方法为插入法,我们可以这样想像,将数组中的元素按顺序逐个插入一个二叉树中,如插入A[0]为根节点,接着插入A[1]为左孩子节点并和根节点A[0]比较,如果不符合最大堆,则A[1]和根节点A[0]交换值;同样,插入A[2];插入A[3],和根节点A[1]比较,如果不符合最大堆,A[3]和A[1]交换值,此时,还需要继续往“总根”方向比较,比较A[1]和A[0],根据最大堆的性质决定是否要交换值,其他节点插入同理。
插入法创建最大堆C++代码:
void Max_Heap_Insert(unsigned A[], unsigned position)
{
unsigned P=position;
unsigned parent = (position - 1) / 2;
while (P > 0 && A[parent] < A[P])
{
unsigned temp = A[P];
A[P] = A[parent];
A[parent] = temp;
P = parent;
parent = (P - 1) / 2;
}
}

void Build_Max_Heap(unsigned A[],unsigned n)
{
for (unsigned i = 1; i < n; ++i)
{
Max_Heap_Insert(A, i);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: