您的位置:首页 > 其它

第6章 堆排序

2012-06-17 15:42 281 查看
一、概念

堆是一种数组对象,却被视频一棵完全二叉树

二、程序

#include <iostream>
#include <stdio.h>
using namespace std;

#define PARENT(i) (i)>>1
#define LEFT(i) (i)<<1
#define RIGHT(i) ((i)<<1)+1

int length = 10;//数组中元素的个数
int heap_size = 10;//属于堆的元素个数,看到HeapSort就会明白

/******************其它************************************/
void Print(int *A)
{
int i;
for(i = 1; i <= length; i++)
{
if(i > 1)cout<<',';
else cout<<"==> A = {";
cout<<A[i];
}
cout<<'}'<<endl;;
}

/*************************以下是堆处理函数****************************************/
//使以i结点为根结点的子树成为堆,调用条件是确定i的左右子树已经是堆,时间是O(lgn)
//递归方法
void Max_Heapify(int *A, int i)
{
int l = LEFT(i), r = RIGHT(i), largest;
//选择i、i的左、i的右三个结点中值最大的结点
if(l <= heap_size && A[l] > A[i])
largest = l;
else largest = i;
if(r <= heap_size && A[r] > A[largest])
largest = r;
//如果根最大,已经满足堆的条件,函数停止
//否则
if(largest != i)
{
//根与值最大的结点交互
swap(A[i], A[largest]);
//交换可能破坏子树的堆,重新调整子树
Max_Heapify(A, largest);
}
}
//非递归方法
void Max_Heapify2(int *A, int i)
{
int l = (LEFT(i)), r = (RIGHT(i)), largest;
//选择i、i的左、i的右三个结点中值最大的结点
if(l <= heap_size && A[l] > A[i])
largest = l;
else largest = i;
if(r <= heap_size && A[r] > A[largest])
largest = r;
//如果根最大,已经满足堆的条件,函数停止
//否则
while(largest != i)
{
//根与值最大的结点交互
swap(A[i], A[largest]);
//交换可能破坏子树的堆,重新调整子树
i = largest;
l = (LEFT(i)), r = (RIGHT(i));
//选择i、i的左、i的右三个结点中值最大的结点
if(l <= heap_size && A[l] > A[i])
largest = l;
else largest = i;
if(r <= heap_size && A[r] > A[largest])
largest = r;
}
}

//建堆,时间是O(nlgn)
void Build_Max_Heap(int *A)
{
heap_size = length;
//从堆中最后一个元素开始,依次调整每个结点,使符合堆的性质
for(int i = length / 2; i >= 1; i--)
Max_Heapify(A, i);
}
//堆排序,时间是O(nlgn)
void HeapSort(int *A)
{
//建立一个最大堆
Build_Max_Heap(A);
//每次将前i个元素构成最大堆
for(int i = length; i > 1; i--)
{
//将前i个元素中的最大值存入到A[i]中
swap(A[1], A[i]);
//堆的大小减一
heap_size--;
//只有堆顶的性质可能会被破坏
Max_Heapify(A, 1);
}
}

/**********************以下是优先队列处理函数****************************************/
//将元素i的关键字增加到key,要求key>=A[i]
void Heap_Increase_Key(int *A, int i, int key)
{
if(key < A[i])
{
cout<<"new key is smaller than current key"<<endl;
exit(0);
}
A[i] = key;
//跟父比较,若A[PARENT(i)]<A[i],则交换
//若运行到某个结点时A[PARENT(i)]>A[i],就跳出循环
while([PARENT(i)] > 0 && A[PARENT(i)] < A[i])
{
swap(A[PARENT(i)], A[i]);
i = PARENT(i);
}
}
//把key插入到集合A中
void Max_Heap_Insert(int *A, int key)
{
if(heap_size == 99)
{
cout<<"heap is full"<<endl;
exit(0);
}
heap_size++;length++;
A[heap_size] = -0x7fffffff;
Heap_Increase_Key(A, heap_size, key);
}
//返回A中最大关键字,时间O(1)
int Heap_Maximum(int *A)
{
return A[1];
}
//去掉并返回A中最大关键字,时间O(lgn)
int Heap_Extract_Max(int *A)
{
if(heap_size < 1)
{
cout<<"heap underflow"<<endl;
exit(0);
}
//取出最大值
int max = A[1];
//将最后一个元素补到最大值的位置
A[1] = A[heap_size];
heap_size--;
//重新调整根结点
Max_Heapify(A, 1);
//返回最大值
return max;
}
//删除堆中第i个元素
void Heap_Delete(int *A, int i)
{
if(i > heap_size)
{
cout<<"there's no node i"<<endl;
exit(0);
}
//把最后一个元素补到第i个元素的位置
int key = A[heap_size];
heap_size--;
//如果新值比原A[i]大,则向上调整
if(key > A[i])
Heap_Increase_Key(A, i, key);
else//否则,向下调整
{
A[i] = key;
Max_Heapify(A, i);
}
}

int main()
{
cin>>length;
heap_size = length;
int A[100], i;
for(i = 1; i <= length; i++)
cin>>A[i];
Print(A);
//	Max_Heapify(A, 3);
//	Build_Max_Heap(A);
//	HeapSort(A);
//	Heap_Extract_Max(A);
//	Max_Heap_Insert(A, 10);
return 0;
}


三、练习

6.1

6.1-1
最多2^(h+1) - 1, 最少2 ^ h
6.1-2
根据上一题,2^h <= n <= 2^(h+1) - 1 ==> h <= lgn <= h + 1 ==> lgn = h
这两题中,当树只有一个结点时,高度是0
6.1-4
叶子上
6.1-5
是最小堆或最大堆
6.1-6
不是,7是6的左孩子,但7>6


6.2

6.2-1
A = {27,17,3,16,13,10,1,5,7,12,4,8,9,0}
==> A = {27,17,10,16,13,3,1,5,7,12,4,8,9,0}
==> A = {27,17,10,16,13,9,1,5,7,12,4,8,3,0}
6.2-2
MIN-HEAPIFY(A, i)
1    l <- LEFT(i)
2    r <- RIGHT(i)
3    if l <= heap-size[A] and A[l] < A[i]
4        then smallest <- l
5        else smallest <- i
6    if r <= heap-size[A] and A[r] < [smallest]
7        then smallest <- r
8    if smallest != i
9        then exchange A[i] <-> A[smallest]
10                MIN_HEAPIFY(A, smallest)
6.2-3
没有效果,程序终止
6.2-4
i > heap-size[A]/2时,是叶子结点,也没有效果,程序终止
6.2-5 我还是比较喜欢用C++,不喜欢用伪代码
void Max_Heapify(int *A, int i)
{
int l = (LEFT(i)), r = (RIGHT(i)), largest;
//选择i、i的左、i的右三个结点中值最大的结点
if(l <= heap_size && A[l] > A[i])
largest = l;
else largest = i;
if(r <= heap_size && A[r] > A[largest])
largest = r;
//如果根最大,已经满足堆的条件,函数停止
//否则
while(largest != i)
{
//根与值最大的结点交互
swap(A[i], A[largest]);
//交换可能破坏子树的堆,重新调整子树
i = largest;
l = (LEFT(i)), r = (RIGHT(i));
//选择i、i的左、i的右三个结点中值最大的结点
if(l <= heap_size && A[l] > A[i])
largest = l;
else largest = i;
if(r <= heap_size && A[r] > A[largest])
largest = r;
}
}


6.3

6.3-1
A = {5,3,17,10,84,19,6,22,9}
==> A = {5,3,17,22,84,19,6,10,9}
==> A = {5,3,19,22,84,17,6,10,9}
==> A = {5,84,19,22,3,17,6,10,9}
==> A = {84,5,19,22,3,17,6,10,9}
==> A = {84,22,19,5,3,17,6,10,9}
==> A = {84,22,19,10,3,17,6,5,9}
6.3-2
因为MAX-HEAPIFY中使用条件是当前结点的左孩子和右孩子都是堆


6.4

6.4-1
A = {5,13,2,25,7,17,20,8,4}
==> A = {25,13,20,8,7,17,2,5,4}
==> A = {4,13,20,8,7,17,2,5,25}
==> A = {20,13,17,8,7,4,2,5,25}
==> A = {5,13,17,8,7,4,2,20,25}
==> A = {17,13,5,8,7,4,2,20,25}
==> A = {2,13,5,8,7,4,17,20,25}
==> A = {13,8,5,2,7,4,17,20,25}
==> A = {4,8,5,2,7,13,17,20,25}
==> A = {8,7,5,2,4,13,17,20,25}
==> A = {4,7,5,2,8,13,17,20,25}
==> A = {7,4,5,2,8,13,17,20,25}
==> A = {2,4,5,7,8,13,17,20,25}
==> A = {5,4,2,7,8,13,17,20,25}
==> A = {2,4,5,7,8,13,17,20,25}
==> A = {4,2,5,7,8,13,17,20,25}
==> A = {2,4,5,7,8,13,17,20,25}
==> A = {2,4,5,7,8,13,17,20,25}
6.4-3
按递增排序的数组,运行时间是nlgn
按递减排序的数组,运行时间是n


6.5

6.5-1
A = {15,13,9,5,12,8,7,4,0,6,2,1}
==> A = {1,13,9,5,12,8,7,4,0,6,2,1}
==> A = {13,1,9,5,12,8,7,4,0,6,2,1}
==> A = {13,12,9,5,1,8,7,4,0,6,2,1}
==> A = {13,12,9,5,6,8,7,4,0,1,2,1}
return 15
6.5-2
A = {15,13,9,5,12,8,7,4,0,6,2,1}
==> A = {15,13,9,5,12,8,7,4,0,6,2,1,-2147483647}
==> A = {15,13,9,5,12,8,7,4,0,6,2,1,10}
==> A = {15,13,9,5,12,10,7,4,0,6,2,1,8}
==> A = {15,13,10,5,12,9,7,4,0,6,2,1,8}
6.5-3
HEAP-MINIMUM(A)
1    return A[1]
HEAP-EXTRACR-MIN(A)
1    if heap-size[A] < 1
2        then error "heap underflow"
3    min <- A[1]
4    A[1] <- A[heap-size[A]]
5    heap-size[A] <- heap-size[A] - 1
6    MIN-HEAPIFY(A, 1)
7    return min
HEAP-DECREASE-KEY(A, i, key)
1    if key > A[i]
2        then error "new key is smaller than current key"
3    A[i] <- key
4    while i > 1 and A[PARENT(i)] > A[i]
5        do exchange A[i] <-> A[PARENT(i)]
6              i <- PARENT(i)
MIN-HEAP-INSERT
1    heap-size[A] <- heap-size[A] + 1
2    A[heap-size[A]] <- 0x7fffffff
3    HEAP-INCREASE-KEY(A, heap-size[A], key)
6.5-4
要想插入成功,key必须大于这个初值。key可能是任意数,因此初值必须是无限小
6.5-6
FIFO:以进入队列的时间作为权值建立最小堆
栈:以进入栈的时间作为权值建立最大堆
6.5-7
void Heap_Delete(int *A, int i)
{
if(i > heap_size)
{
cout<<"there's no node i"<<endl;
exit(0);
}
int key = A[heap_size];
heap_size--;
if(key > A[i])   //最后一个结点不一定比中间的结点最
Heap_Increase_Key(A, i, key);
else
{
A[i] = key;
Max_Heapify(A, i);
}
}


6.5-8算法导论6.5-8堆排序

四、思考题

6-1

a)A = [1,2,3];

6-2

a)

根结点是A[1],根结点的孩子是A[2]-A[d+1],……

PARENT(i) = (i - 2 ) / d + 1

CHILD(i, j ) = d * (i - 1) + j + 1

b)lgn/lgd

c)

HEAP-EXTRACR-MAX(A)
1    if heap-size[A] < 1
2        then error "heap underflow"
3    max <- A[1]
4    A[1] <- A[heap-size[A]]
5    heap-size[A] <- heap-size[A] - 1
6    MAX-HEAPIFY(A, 1)
7    return max
MAX-HEAPIFY(A, i)
1    largest <- A[i]
2    for j = i to j+i+d-j
3        if j <= heap-size[A] and A[j] > A[i]
4            largest <- j
5    if largest != i
6    then exchange A[i] <-> A[largest]
7             MAX-HEAPIFY(A, largest)
时间复杂度是O(lgn/lgd * d)

d)和二叉堆的实现完全一样,时间复杂度是O(lgn/lgd)

e)和二叉堆的实现完全一样,时间复杂度是O(lgn/lgd)

6-3

a)不唯一
2345
8912
1416
c)

YOUNG-EXTRACR-MIN(Y)
1    if  Y[1][1] == 0X7FFFFFFF
2        then error "heap underflow"
3    min <- Y[1][1]
4    A[1][1] <- 0X7FFFFFFF
5    MAX-HEAPIFY(Y, 1, 1)
6    return min
MIN-YOUNGIFY(Y, i, j)
1    min <- Y[i][j]
2    if i < m and Y[i+1][j] < min
3        mini <- i+1
4        minj <- j
5        min <- Y[i+1][j]
6    if j < n and Y[i+1][j+1] < min
7        mini <- i
8        minj <- j+1
9        min <- Y[i][j+1]
10    if i != mini and j != minj
11        exchange Y[i][j] <-> Y[mini][minj]
12        MIN-YOUNGIFY(Y, mini, minj)


d)

MIN-YOUNG-INSERT(Y, key)
1    if Y[m]
< 0x7fffffff
2        then error "young overflow"
3    Y[m]
<- key
4    flag <-  true
5    i <- m
6    j <- n
7    max <- key
8    while flag == true
9        if i > 1 and max < Y[i-1][j]
10            maxi <- i - 1
11            maxj <- j
12            max <- Y[i-1][j]
13        if j > 1 and max < Y[i][j-1]
14            maxi <- i
15            maxj <- j-1
16            max <- Y[i][j-1]
17        if max == key
18            flag = false
19        exchange Y[maxi][maxj] <-> Y[i][j]
20        i <- maxi
21        j <- maxj
f)
FIND-YOUNG-KEY(Y, key)
1    i<- 1
2    j <- 1
3    while i <=m or j <= n
4        if key == Y[i][j]
5        then return true
6        if key < Y[i][j]
7        then return false
8        else
9            if i < m and Y[i+1][j] < key
10                i <- i + 1
11            else if j < n and Y[i][j+1] < key
12                j <- j + 1
13            else return false
14    return false
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: