堆的简述以及堆排序

来源:互联网 发布:17年机械行业数据 编辑:程序博客网 时间:2024/06/18 10:29

堆的定义:

堆是一个数组,是一个近似的完全二叉树(算法导论的定义,不同的书籍对XX二叉树有着不同的定义,请注意),即除了最低层外,该树是完满的,并且最底层是从左到右依次填充。

通过定义可以看出,堆数组是没有“洞的”,每个有效数字都是紧挨着的!

堆的性质:

最大堆值的是对于当前下标i,有left(i)和right(i)两棵子树,且保证下标i对应的值比两棵子树所有的值都大。

最小堆与上述定义相反。


构造堆:

为了构造堆,我们需要对所有非叶子节点(叶子结点没有子节点,满足堆的性质),自底向上地逐个进行处理,要维护好堆的性质。

堆排序:

对一个满足堆性质的数组(即堆),每次取出根节点与最后一个结点交换,然后重新对根节点维护堆的性质,最后堆数组的大小要减一,因为被交换到后面的数组是有序的,不符合堆的性质。

伪代码:

heapSort()

1.  对数组进行堆的构造

2.  for i=最后一个结点的下标 downto 1

3.         交换A[0]和A[i]

4.         堆的有效长度减1

5.         对根结点进行堆的维护 


具体代码:
import java.util.Arrays;/*根节点下标为0*/public class Heap {private int[] arr;private int arr_length; //数组长度private int size; //堆的有效长度,即arr[0-size]满足堆的性质public Heap(int[] arr){this.arr = arr;arr_length = arr.length;size = arr.length;}//获得左子节点下标private int getLeftChild(int index){return 2*index+1;}private int getRightChild(int index){return 2*index+2;}//获得父节点下标private int getParent(int index){return (index-1)/2;}//维护最大堆的性质public void max_heapify(int index){int left = getLeftChild(index);int right = getRightChild(index);int largest = index;  //largest记录index、它的左子节点、它的右子节点对应值最大的下标if(left<size&&arr[left]>arr[index]){largest = left;}else largest = index;if(right<size&&arr[right]>arr[largest]){largest = right;}//若largest不是index,交换后,arr[largest]变小了,可能会破坏了堆的性质,所以要继续对此维护if(largest!=index){int temp = arr[largest];arr[largest] = arr[index];arr[index] = temp;max_heapify(largest);}}//构造最大堆public void build_heap(){//从数组最后一个节点的父节点的右边第一个节点开始,到最后一个节点都是叶节点for(int i=getParent(size-1);i>=0;i--){max_heapify(i);}}//堆排序public void heapSort(){build_heap();//先对数组进行堆的构造for(int i=size-1;i>=1;i--){int temp = arr[0];arr[0] = arr[i];arr[i] = temp;size--; //易错点,堆数组有效个数减一,因为交换过后,i后面的数都是升序的,不符合最大堆的性质max_heapify(0);}}public static void main(String[] args){int[] arr = new int[(int)(Math.random()*50)];for(int i=0;i<arr.length;i++){arr[i] = (int)(Math.random()*50);}Heap heap = new Heap(arr);heap.heapSort();System.out.println(Arrays.toString(arr));}}


原创粉丝点击