当前位置:   article > 正文

堆的定义,堆与树的区别,堆排序(Java实现)_堆和树的区别

堆和树的区别

堆的定义(Heap)

堆是一个特殊的数据结构,可以看作是用数组实现的二叉树。

它是一个完全二叉树,除了树的最后一层结点不需要是满的,其它的每一层从左到右都是满的,如果最后一层结点不 是满的,那么要求左满右不满。

数组实现的具体方法就是将二叉树的结点按照层级顺序放入数组中,根结点在位置1,它的子结点在位置2和3,而子结点的子结点则分别在位置4,5,6和7,以此类推。

堆的每个结点都大于等于它的两个子结点。这里要注意堆中仅仅规定了每个结点大于等于它的两个子结点,但这两个子结点的顺序并没有做规定,跟二叉查找树是有区别的。 

怎么去确定结点位置呢?如果一个结点的位置为k,则它的父结点的位置为k/2,而它的两个子结点的位置则分别为2k和2k+1。这样在不使用指针的情况下,我们也可以通过计算数组的索引在树中上下移动:从a[k]向上一层,就令k等于k/2,向下一层就令k等于2k或2k+1。 

 

堆与树之间的区别

结点的排序:在二叉查找树中,左子节点必须比父节点小,右子节点必须必比父节点大。但是在堆中并非如此,在最大堆中两个子节点都必须比父节点小,而在最小堆中,它们都必须比父节点大,就像是从大到小或者从小排序的一个数组。

内存占用:普通的树所占用的内存会更多,因为它需要指针,指向左右子结点,而堆不用,只需要储存一个数组就可以了,因为它规定了子父结点之间的关系。

平衡以及作用:普通的树更强调平衡性,只有在平衡的时候,树的快速查找才能体现出来,而堆并不需要,它更多的是利用堆排序来进行增删,它们的职能是不一样的。

 

堆的API设计(最大堆)

 

 

  1. public class Heap<T extends Comparable<T>> {
  2. private T[] items;
  3. private int N;
  4. public Heap(int capacity) {
  5. //capacity+1是因为索引从1开始储存数据
  6. this.items = (T[]) new Comparable[capacity + 1];
  7. this.N = 0;
  8. }
  9. // 判断索引i处的值是否小于索引j处的值
  10. private boolean less(int i,int j){
  11. return items[i].compareTo(items[j])<0;
  12. }
  13. // 交换i处和j处的值
  14. private void exchange(int i,int j){
  15. T temp = items[i];
  16. items[i]=items[j];
  17. items[j]=temp;
  18. }
  19. // 往堆中插入元素
  20. public void insert(T t){
  21. items[++N]=t;
  22. //添加之后进行上浮排序
  23. swim(N);
  24. }
  25. // 删除堆中最大的元素,并返回这个最大元素
  26. public T delMax(){
  27. //就是将第一个元素和最后一个元素交换,再让最后索引为null,最后下沉第一个元素
  28. T max = items[1];
  29. exchange(1,N);
  30. items[N] = null;
  31. N--;
  32. // 通过下沉算法调整堆的排序
  33. sink(1);
  34. return max;
  35. }
  36. // 上浮算法,使得添加的元素在合适的位置
  37. public void swim(int k){
  38. // 通过循环不断比较与父结点的大小,若比父结点大,就换位置上浮
  39. while (k > 1) {
  40. if (less(k/2,k)){
  41. exchange(k/2,k);
  42. }
  43. k=k/2;
  44. }
  45. }
  46. // 下沉算法
  47. private void sink(int k){
  48. // 通过循环不断比较当前结点k与其左子结点2k和右子结点2k+1中的较大值
  49. while (2*k<=N){
  50. int max;
  51. if (2 * k + 1 <= N) {
  52. if (less(2*k,2*k+1)){
  53. max=2*k+1;
  54. }else {
  55. max=2*k;
  56. }
  57. }else {
  58. max=2*k;
  59. }
  60. if (!less(k,max)){
  61. break;
  62. }
  63. exchange(k,max);
  64. k=max;
  65. }
  66. }
  67. }

 

堆排序

排序原理:堆排序分为两个过程,一个是堆有序的构建,二是堆的排序。

  1. 首先在堆索引的一半处开始倒叙遍历,对得到的每一个元素做下沉操作,得到一个有序的完全二叉树(此时只是树形结构上的有序,而不是堆的有序)。
  2. 再通过将首结点与末结点交换,在排除此时末结点的范围内对首结点进行下沉,往复筛选全部元素的方法,实现堆排序。

 

 

堆排序的API设计

  1. public class HeapSort {
  2. //对source数组中的数据从小到大排序
  3. public static void sort(Comparable[] source) {
  4. //创建一个比原数组大1的数组
  5. Comparable[] heap = new Comparable[source.length + 1];
  6. //构造堆
  7. createHeap(source,heap);
  8. //堆排序
  9. //定义一个变量,记录heap中未排序的所有元素中最大的索引
  10. int N = heap.length-1;
  11. while(N!=1){
  12. //交换heap中索引1处的元素和N处的元素
  13. exchange(heap,1,N);
  14. N--;
  15. //对索引1处的元素在0~N范围内做下沉操作
  16. sink(heap,1,N);
  17. }
  18. //heap中的数据已经有序,拷贝到source中
  19. System.arraycopy(heap,1,source,0,source.length);
  20. }
  21. // 根据原数组source,构造出堆heap
  22. private static void createHeap(Comparable[] source,Comparable[] heap){
  23. System.arraycopy(source,0,heap,1,source.length);
  24. //2.从heap索引的一半处开始倒叙遍历,对得到的每一个元素做下沉操作
  25. for (int i=(heap.length)/2;i>0;i--){
  26. sink(heap,i,heap.length-1);
  27. }
  28. }
  29. //判断heap堆中索引i处的元素是否小于索引j处的元素
  30. private static boolean less(Comparable[] heap,int i,int j){
  31. return heap[i].compareTo(heap[j])<0;
  32. }
  33. //交换heap堆中i索引和j索引处的值
  34. private static void exchange(Comparable[] heap,int i, int j){
  35. Comparable tem= heap[i];
  36. heap[i]=heap[j];
  37. heap[j]=tem;
  38. }
  39. // 在堆heap中对目标元素进行下沉,范围为range
  40. private static void sink(Comparable[] heap,int target,int range){
  41. //有子结点
  42. while (2 * target <= range) {
  43. int max=0;
  44. //有两个子结点
  45. if (2 * target + 1 <= range) {
  46. if (less(heap,2*target,2*target+1)){
  47. max=2*target+1;
  48. }else {
  49. max=2*target;
  50. }
  51. }else {
  52. max=2*target;
  53. }
  54. if (less(heap,target,max)){
  55. exchange(heap,target,max);
  56. }
  57. // 为了继续下一个循环
  58. target=max;
  59. }
  60. }
  61. }

 

 

 

 

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/538442
推荐阅读
相关标签
  

闽ICP备14008679号