当前位置:   article > 正文

二叉树(堆和优先队列)_优先队列来遍历二叉树

优先队列来遍历二叉树

堆是一种特殊的二叉树

最小值堆:最小值堆的特性。

对于堆的任意非叶节点K,K的值总是小于或者等于左右子节点。

K <= 左节点;K <= 又节点;

堆实例:

堆实际上是一个完全二叉树(若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。)可以用数组表示。

堆中存储是局部有序的。

创建堆:

交换创建堆,交换有2,1)向下交换,2)向上交换。

1)向下交换。

假设根的左右子树都已是堆,并且根元素为R,此时有2种情况。

  (1)R的值小于或者等于左右子结点,此时堆完成。

  (2)R的值大于其中一个或者两个子女,此时R应该与两个子女中较小的一个交换,结果得到一个新堆,

R到达新位置后继续和其两个子女,如果R小于或者等于其左右子女,建堆完成,否则重复上一过程,直到

R小于或等于其左右子女,或R成为新的叶结点。

 

堆的数组实现:

  1. public abstract class AbstractHeap<T extends Comparable<T>> implements Heap<T> {
  2. //最大堆大小
  3. private static final int MAX_SIZE = Integer.MAX_VALUE;
  4. //数组大小
  5. protected int size;
  6. //堆中数组个数
  7. protected int currentSize;
  8. //存储堆的数据
  9. protected T[] data;
  10. AbstractHeap(){
  11. this(0,16,null);
  12. }
  13. AbstractHeap(T[] data){
  14. this(data.length,data.length,data);
  15. }
  16. AbstractHeap(int currentSize,int size,T[] data){
  17. this.currentSize = currentSize;
  18. this.size = size;
  19. this.data = data;
  20. if (data != null)
  21. //根据给定数组 创建堆
  22. buildHeap(data);
  23. }
  24. }

用给定的数组创建堆,从堆中第一个分支结点,从下往上网上交换创建堆:

  1. private void buildHeap(T[] t){
  2. if (t.length > 1){
  3. //从下到上第一个分支结点
  4. int pos = t.length / 2 - 1;
  5. for (int i = pos ; i >= 0 ; i -- ){
  6. //向下交换
  7. siftDown(i);
  8. }
  9. }
  10. }

交换函数:

  1. void siftDown(int pos) {
  2. // pos为第一个分支结点位置
  3. int tmp = pos;
  4. // j为其左结点
  5. int j = tmp * 2 + 1;
  6. //保存当前结点值
  7. T tmpNode = data[tmp];
  8. while ( j < currentSize){
  9. //j < currentSize - 1 防止右结点不存在,j+1 = tmp *2 +1 ,data[j+1] 为右结点
  10. if (j < currentSize - 1 && data[j].compareTo(data[j+1]) == 1){
  11. //若右结点值比较小,j++
  12. j++;
  13. }
  14. if (tmpNode.compareTo(data[j]) == 1){
  15. //若当前结点值大于左右结点中最小的值,将最小的哪个结点值上移当前结点,
  16. data[tmp] = data[j];
  17. //tmp 为上移结点下标
  18. tmp = j;
  19. j = j * 2 + 1;
  20. }
  21. //如果当前结点值小于其左右子女中最小的,建堆完成,跳出循环
  22. else break;
  23. //将当前结点值 赋值给上移结点
  24. data[tmp] = tmpNode;
  25. }
  26. }

2)向上交换

在堆中新增值时,采用向上交换:

  1. public boolean insert(T t) {
  2. if (t == null){
  3. return false;
  4. }
  5. if (currentSize == size){
  6. return false;
  7. }
  8. //直接将新增值放到数组的最后一个位置,并向上交换
  9. data[currentSize] = t;
  10. siftUp(currentSize);
  11. currentSize ++;
  12. return true;
  13. }
  1. void siftUp(int pos) {
  2. //当前位置下标
  3. int tmp = pos;
  4. //父结点下标
  5. int j = (pos - 1) / 2;
  6. //当前结点
  7. T tmpNode = data[tmp];
  8. while (j >= 0){
  9. //如果当前结点值小于父结点,当前结点值向上移动,直到根结点或者当前结点值打于根结点值跳出循环
  10. if (tmpNode.compareTo(data[j]) == -1){
  11. data[tmp] = data[j];
  12. tmp = j;
  13. j = j / 2 - 1;
  14. }else break;
  15. tmpNode = data[tmp];
  16. }
  17. }

创建堆可以根据已有数据创建采用向下移动创建,也可以一个一个的插入值,采用向上移动的方法创建堆。

小结:

堆的特性,父结点的值小于左右子女结点值。

堆保持局部有序性,可以用左优先队列

堆排序时间复杂度为O(n)

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号