java 计算父亲节,基本算法-堆排序及其Java实现

(二叉)堆(heap)数据结构是一种数组对象,可以视作一颗完全二叉树,从该二叉树的根开始层次遍历这颗二叉树就可以得到其对应的数组。树的根节点为A[0],对于树中某个节点的坐标i,其左右孩子节点和父亲节点的坐标可以很方便的求得:

LEFT(i)=2*i+1; RIGHT(i)=2*i+2; PARENT(i)=i/2 .

有两种二叉堆:最大堆和最小堆。最大堆中,每个节点存储的数值都大于等于其左右两个孩子节点存储的数值,亦即A[i]>=A[LEFT[i]]&&A[i]>=A[RIGHT[i]]。最小堆则正好相反。本文以最大堆为例。

知道了最大堆的定义之后,就要在给定的任意数组上构建最大堆,然后利用这个最大堆进行升序排序:

(1) 构建最大堆:

首先我们定义一个方法Heapify(heap,i),如果以i的左右孩子节点为根的子树已经是最大堆,则该方法使得以i为根的子树也成为最大堆。其伪代码如下(摘自《算法导论》):

1

MAX-

HEAPIFY(A,i)

2

l=

LEFT(i)

3

r=

RIGHT(i)

4

target=

i;

5

if

(l<=A.heap_size&&A[l]>

A[i])

6

target=

l;

7

if

(

if

(r<=A.heap_size&&A[r]>

A[i]))

8

target=

r;

9

if

(target!=

i)

10

exchange(A[i],A[target])

11

MAX-HEAPIFY(A,target)//递归

我们比较当前节点i的数值和其左右子节点的数值,如果i的某个子节点的数值大于i的数值,则违反了最大堆的定义,所以我们需要交换这两个节点的位置。假设A[LEFT[i]]>A[RIGHT[i]]>A[i],则交换i节点与LEFT[i]节点。但是,被交换到左孩子节点的i节点可能会违反以左孩子结点为根的最大堆的定义,所以我们需要对这个最大堆递归调用MAX-HEAPIFY方法。

有了上面这个方法之后,我们就可以自底向上的调用MAX-HEAPIFY方法构建最大堆。因为A[A.length/2+1]及其之后的节点都是叶子节点,都可以看做只有一个节点的最大堆,所以我们可以从A[A.length/2]节点开始直到A[0]节点依次调用MAX-HEAPIFY方法,亦即从树的层次遍历的最后一个有孩子的节点开始,按照层次遍历的逆序调用MAX-HEAPIFY方法:

1

BUILD-MAX-

HEAP(A)

2

for

i=A.length/

2

downto

1

3

MAX-HEAPIFY(A,i)

(2) 堆排序

构造完最大堆之后,我们就可以利用其进行排序。因为最大堆只能保证A[0]存储的是当前堆中最大的元素,我们可以把A[0]与堆的最后一个元素互换,这样A[0]就排在了最后一个位置,也是正确的位置。这时最后一个位置已经不属于最大堆,所以A.heap_size要减一。互换到A[0]的元素可能会破坏最大堆的性质,我们可以调用MAX-HEAPIFY方法使之重新成为最大堆,然后将A[0]交换至当前堆的最后一个位置。依次递归。

1

HEAPSORT(A)

2

for

i=A.length downto

2

3

exchange(A[i],A[

0

])

4

--A.heap_size

//

堆的大小减少

5

MAX-HEAPIFY(A,

0

)

(3) 堆的JAVA实现

1

package

Algorithm;

2

3

import

java.util.*

;

4

/**

5

* 堆(Heap)

6

*

@author

Kemaswill

7

* 2012-10-5 Friday

8

*/

9

10

public

class

Heap {

11

12

public

static

int

[] data;

13

public

static

int

length;

14

public

static

int

heap_size;

15

16

public

Heap(){

17

this

.length=20

;

18

this

.heap_size=

length;

19

this

.data=

new

int

[length];

20

Random random=

new

Random(System.currentTimeMillis());

21

for

(

int

i=0;i

){

22

data[i]=Math.abs(random.nextInt()%50

);

23

}

//

for

24

}

25

26

public

Heap(

int

n){

27

this

.length=

n;

28

this

.heap_size=

length;

29

this

.data=

new

int

[length];

30

Random random=

new

Random(System.currentTimeMillis());

31

for

(

int

i=0;i

){

32

data[i]=Math.abs(random.nextInt()%50

);

33

}

//

for

34

}

35

36

public

static

void

max_heapify(Heap heap,

int

i){

37

if

(i<

heap.heap_size){

38

int

l=2*i+1

;

39

int

r=2*i+2

;

40

int

target=

i;

41

if

(l

heap.data[i]){

42

target=

l;

43

}

44

if

(r

heap.data[target]){

45

target=

r;

46

}

47

if

(target!=

i){

48

exchange(heap,i,target);

49

max_heapify(heap,target);

50

}

//

if

51

}

//

if

52

}

//

heapify

53

54

public

static

void

exchange(Heap heap,

int

x,

int

y){

55

int

tmp=

heap.data[x];

56

heap.data[x]=

heap.data[y];

57

heap.data[y]=

tmp;

58

}

59

60

public

static

void

build_heap(Heap heap){

61

//

对于所有非叶结点,依次调用max_heapify

62

for

(

int

i=heap.heap_size/2;i>=0;i--

){

63

max_heapify(heap,i);

64

}

65

}

66

67

public

static

void

heapsort(Heap heap){

68

69

for

(

int

i=heap.length-1;i>0;i--

){

70

exchange(heap,0

,i);

71

heap.heap_size--

;

72

max_heapify(heap,0

);

73

}

74

}

//

heapsotr

75

76

public

static

void

show_heap(Heap heap){

77

for

(

int

i=0;i<=(

int

)Math.log(heap.length)/Math.log(2)+2;i++

){

78

for

(

int

j=(

int

)Math.pow(2, i)-1;j

){

79

if

(j<

heap.length){

80

System.out.print(heap.data[j]+" "

);

81

}

82

else

break

;

83

}

84

System.out.println();

85

}

86

}

87

88

public

static

void

main(String[] args){

89

Heap heap=

new

Heap();

90

show_heap(heap);

91

build_heap(heap);

92

show_heap(heap);

93

heapsort(heap);

94

show_heap(heap);

95

96

}

//

main

97

98

}

参考文献:

[1] 《算法导论》 第6章 p73

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值