算法基础三:分治算法---堆的实现与堆排序
算法基础三:分治算法---堆的实现与堆排序
一、堆的概念及其创建
1、二叉堆的概念
(二叉)堆(heap)数据结构是一个数组对象,它可以被视为是一个几乎完全的二叉树。树中的每一个节点对应于数组中的一个元素,该元素存储了节点的值。该树除了最底层,几乎完全填满了,最底层的填充是从左到右进行的。表示堆的数组A具有两个域:length[A],它表示数组中的元素个数;heap-size[A],它表示存储于A中的堆的元素个数,它们之间具有heap-size[A]<=length[A]的关系。
树的根是A[1],对给定节点的下标i,其父亲的下标PARENT(i),左子树的下标LEFT(i),右子树的下标RIGHT(i)可以直接计算:
PARENT(i)
return [i/2]
LEFT(i)
return 2i
RIGHT(i)
return 2i+1
特点:
- 父节点总是位于孩子的左边
- 树的高度为3
- 下标为4的节点(值为8)的高度为1
2、二叉堆的分类
最大堆和最小堆,两种堆中节点的值都要满足堆的性质,区别在于堆的类型。
①最大堆
在最大堆中,最大堆的性质是对每一个非根节点 i,
A[PARENT(i)] >= A[i]
即节点的值至多为其父亲的值。于是最大堆中的最大元素就存储在根中,而以某节点为根的子树中所含的所有节点值不会大于该节点的值。
②最小堆
最小堆以相反的形式组织,最小堆性质是对每一个非根节点 i,
A[PARENT(i)]<=A[i]
最小堆中的最小元素就是根。
如果只有一个元素,也可以看做一个堆,称为单元素堆。
二、二叉堆性质维护问题描述
1、问题描述
2、伪代码描述
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)
三、二叉堆创建问题描述
1.问题描述
- 输入:数组A[1...n]
- 输出:重排后的数组A[1...n],元素间构成一个堆
2、伪代码描述
利用MAX-HEAPIFY通过自底向上的方式将数组A[1...n]转换成一个最大堆。由于子数组A[(n/2)+1...n]的每一个元素都没有左右孩子,所以都是树的叶子,因此每一个均构成一个单元素堆。过程BUILD-MAX-HEAP检测树种的其余节点并对每个节点运行MAX-HEAPIFY
BUILD-MAX-HEAP(A)
heap-size[A] <- length[A]
for i <- (length[A]/2) downto 1
do MAX-HEAPIFY(A,i)
图例:
四、程序实现
1、Comparable型线性表建立堆(最大/最小)
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class LinearList {
//在实际的数组中,下标从零开始。所以会和伪代码有所不同
public static int left(int i){
return 2*i+1;
}
public static int right(int i){
return 2*i+2;
}
public static int parent(int i){
if (i%2==1)
return i/2;
return i/2-1;
}
public static void heapify(List<Comparable> a, int i, int heapSize, Comparator comp){
int l=left(i),r=right(i),most;
if (l<heapSize && (comp.compare(a.get(l),a.get(i))>0))
most = l;
else
most = i;
if (r<heapSize && (comp.compare(a.get(r),a.get(most))>0))
most = r;
if (most != i){
Collections.swap(a,i,most);
heapify(a,most,heapSize,comp);
}
}
public static void buildHeap(List<Comparable> a,Comparator comp){
int heapSize = a.size();
for (int i=heapSize/2;i>=0;i--)
heapify(a,i,heapSize,comp);
}
}
2、Greater & Less
import java.util.Comparator;
public class Greater implements Comparator<Comparable> {
public int compare(Comparable x, Comparable y){
return x.compareTo(y);
}
}
import java.util.Comparator;
public class Less implements Comparator<Comparable> {
@Override
public int compare(Comparable o1, Comparable o2) {
return o2.compareTo(o1);
}
}
3、测试
import java.util.List;
import java.util.Vector;
public class Test {
public static void main(String[] args) {
int h[] = {4,1,3,2,16,9,10,14,8,7},i;
Vector<Integer> H = new Vector<>();
for (int i1 : h) {
H.add(new Integer(i1));
}
LinearList.buildHeap((List)H,new Greater());
System.out.println("max heap: ");
System.out.println(H);
LinearList.buildHeap((List)H,new Less());
System.out.println("min heap: ");
System.out.println(H);
}
}
五、堆排序
1、算法的描述与分析
图解:
2、程序实现
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Sort {
static public void heapSort(List<Comparable> a, Comparator comp){
int i ,heapSize=a.size();
LinearList.buildHeap(a,comp);
for (i=heapSize-1;i>0;i--){
Collections.swap(a,0,i);
heapSize--;
LinearList.heapify(a,0,heapSize,comp);
}
}
}
3、测试
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
public class TestSort {
public static void main(String[] args) {
Integer a[] = {5,1,9,4,6,2,0,3,8,7},i;
String b[] = {"ChongQing","ShangHai","AoMen","TianJin","BeiJing","XiangGang"};
Double c[] = {8.5,6.3,1.7,9.2,0.5,2.3,4.1,7.4,5.9,3.7};
ArrayList<Integer> A = new ArrayList<>();
Vector<String> B = new Vector<>();
LinkedList<Double> C = new LinkedList<>();
for (Integer integer : a) {
A.add(integer);
}
for (String s : b) {
B.add(s);
}
for (Double aDouble : c) {
C.add(aDouble);
}
Sort.heapSort((List) A,new Less());
Sort.heapSort((List) B,new Less());
Sort.heapSort((List) C,new Greater());
System.out.println(A);
System.out.println(B);
System.out.println(C);
}
}