您的位置:首页 > 理论基础 > 数据结构算法

数据结构基础加强之最小堆的实现与堆排序

2017-05-16 19:15 489 查看
数据结构基础加强之最小堆的实现与堆排序

二叉堆的形式:

最小堆:根结点的值是所有堆结点中最小者,并且每个结点的值比其孩子结点小。

最大堆:根结点的值是所有堆结点中最大者,并且每个结点的值比其孩子结点大。





最小堆通常都是一棵完全二叉树,可以用数组来存储最小堆的值。

堆中父结点与子结点 的关系:

heap[father * 2] = heap[leftChild]; heap[father * 2 + 1] = heap[rightChild];

最大堆与最小堆基本做法基本一致,只要把实现代码中的小于变大于,大于变小于即可。

最小堆的初始化:依次将节点加入堆数组中,每次进入新的结点加到堆数组的尾部,依次与父结点相比较,如果小于父结点则交换二者的位置。

//添加元素
public void add(int item){
size++;
heap[size] = item;
int curr = size;
while (heap[curr] < heap[getFather(curr)]) {
swap(curr,getFather(curr));
curr = getFather(curr);
}
}


最小堆的调整:一处最小堆的根节点之后,需要调整堆数组使之成为一个新的堆。

可以采用以下方式来调整堆:将堆数组最后一个元素放到堆数组的首部,依次与左右子结点比较,把较小的值与根节点交换,然后递归,直至当前节点是叶子节点为止。

//元素下移调整
public void pushDown(int pos){
int smallChild;
while (!isLeaf(pos)) {
smallChild = getLeftChild(pos);
//在父节点知道的情况下,左节点不会出现越界情况,右节点可能越界
if (smallChild <= size) {
if (getRightChild(pos) <= size && heap[smallChild] > heap[smallChild + 1]) {
smallChild++;
}
if (heap[pos] > heap[smallChild]) {
swap(pos,smallChild);
pos = smallChild;
}else {
return;
}
}else {
return;
}
}
}


堆排序的实现:

利用建立的堆实现堆排序比较简单。将数组中的元素依次加入最小堆中,每次取出堆数组的第一个元素,即最小值放到待排序数组的首部。每次取出堆数组第一个元素后,堆数组会自己调整,让它继续是一个最小堆。依次取出最数组的中的第一个元素,依次放入待排序数组中,直至堆数组为空,此时待排序数组是有序的。

堆排序实现代码:

import heap.Heap;

public class HeapSort {

public static void main(String[] args) {

int[] array = { 1, 9, 6, 8, 7, 3, 4, 2, 0 };
solution(array);
for (int i : array) {
System.out.print(i + " ");
}
}

private static void solution(int[] array) {

Heap heap = new Heap(10);
for (int i : array) {
heap.add(i);
}
for (int i = 0;i < array.length;i++) {
array[i] = heap.delete();
}
}

}
最小堆的实现代码:

public class Heap {

private int[] heap;
private int size;//当前节点数
@SuppressWarnings("unused")
private int max; //最大节点数

//使用数组存储堆元素  根节点位于数组下表为1的元素
public Heap(int max){
this.max = max;
heap = new int[max];
size = 0;
heap[0] = Integer.MIN_VALUE;
}
//获得父节点的位置
public int getFather(int index){
return index / 2;
}
//获得左子节点的位置
public int getLeftChild(int index){
return index * 2;
}
//获得右子节点的位置
public int getRightChild(int index){
return index * 2 + 1;
}
//判断节点是否为根节点
public boolean isLeaf(int index){
if (index > size / 2 && index < size) {
return true;
}else{
return false;
}
}
//判断堆是否为空
public boolean isEmpty(){
if (size == 0) {
return true;
}else{
return false;
}
}
//元素交换
public void swap(int pos1,int pos2){
int temp = heap[pos1];
heap[pos1] = heap[pos2];
heap[pos2] = temp;
}
//打印所有节点
public void print(){
for (int i = 1;i <= size;i++) {
System.out.print(heap[i] + " ");
}
}
//添加元素
public void add(int item){
size++;
heap[size] = item;
int curr = size;
while (heap[curr] < heap[getFather(curr)]) {
swap(curr,getFather(curr));
curr = getFather(curr);
}
}
//删除并返回根节点
public int delete(){
int firstItem = heap[1];
swap(1, size);
size--;
if (size != 1) {
pushDown(1);
}
return firstItem;
}
//元素下移调整
public void pushDown(int pos){
int smallChild;
while (!isLeaf(pos)) {
smallChild = getLeftChild(pos);
//在父节点知道的情况下,左节点不会出现越界情况,右节点可能越界
if (smallChild <= size) {
if (getRightChild(pos) <= size && heap[smallChild] > heap[smallChild + 1]) {
smallChild++;
}
if (heap[pos] > heap[smallChild]) {
swap(pos,smallChild);
pos = smallChild;
}else {
return;
}
}else {
return;
}
}
}
}
具体代码可以参考:https://github.com/Li-JY/algorithm-and-datastructure/tree/master/src/heap
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息