Heap

 

   Heap中文翻译过来叫做堆,但他并不是大家所说的内存中的堆栈区,而是一种用数组来实现的弱序的完全二叉树。他是一种数据结构。Heap 很像前面所说的二叉搜索树,但是他并没有二叉搜索树那样有严格的顺序规定。二叉搜索树中,父接点必须大于它的左孩子,而小于他的右孩子;但是在Heap中,只要规定父接点大于两个子接点就可以了,而且其中的每个元素并不是通过Link来连接的,而是对这个完全二叉树进行编号,然后放到数组中。由父接点的编号能找到相应的子接点的编号,反之亦然。

• Its parent is (x–1) / 2
• Its left child is 2*x + 1
• Its right child is 2*x + 2

   Heap的作用可以看成是一个优先级队列,他并不能实现查找某个接点的功能,因为Heap是一个弱序的二叉树,他是搜索不到要找的接点的。但是Heap可以像一个优先级队列一样,支持删除最大(最小)的接点(因为删除都是删除根,而根通常是整个树中最大的或者最小的接点),插入新接点。

  插入接点就是将新接点插入到数组的最后一个位置,也就是二叉树的第1个空位上。然后将这个接点向上遍历,直到找到他合适的位置,也就是第1个大于他的父接点。

  public boolean insert(int key)
  {
         if(arraySize == maxSize)
                  return false;
         Node newNode = new Node(key);
         heapArray[arraySize++] = newNode;
         trickleUp(arraySize);//将这个接点向上遍历,以找到合适的位置
         return true;
}

删除接点就是将root删除,然后将二叉树中的最后一个元素移至root,再向下便利以找到合适的位置。向下遍历比向上遍历要麻烦的一点就是要比较出子接点中较大的,然后再比较此接点,如果小于大点的子接点就和大的子接点互换位置。

public Node remove()
{
         Node temp = heaparray[0];
         heapArray[0] = heapArray[--arraySize];
         tricleDown(0);
         return temp;
}

除了实现了insert 和remove之后,再多实现一个change(),这个方法用于改变特定Node的key,就像在优先级 队列中改变一个元素的优先级别一样。

public boolean change(int key,Node newNode)
{
         if(key<0||key>arraySize)
                    return false;
          Node oldNode = heapArray[key];
          heapArray[key] = newNode;
          if(oldNode.iData<newNode.iData)
                    trickleDown(key);
          else
                    trickleUp(key);
          return true;
}

写到这儿,其实实现Heap最难的无非是trickleDown和trickleUp方法了。

public void trickeUp(int index)
{
         Node temp = heapArray[index];
         parent = index/2;
         while(index>0&&heapArray[index]>heapArray[parent])
         {
                  heapArray[index] = heapArray[parent];
                  index = index/2;
                  parent = index/2;
         }
         heapArray[index] = temp;
}

public void trickleDown(int index)
{
         Node temp = heapArray[index];
         int larger;
         while(index<arraySize/2)
         {
                  if(index*2+2<arraySize&&heapArray[index*2+1]<heapArray[inde*2+2])
                           larger = index*2+2;
                  else
                           larger = index*2+1;
                  if(heapArray[index]>heapArray[larger])
                           break;
                  heapArray[index] = heapArray[larger];
                  index = larger;
         }
         heapArray[index] = temp;
}

### 堆的概念 堆是一种特殊的树形数据结构,在这种结构中,根节点的关键字是所有节点关键字的最大值或者最小值。如果父节点总是大于等于子节点,则称为最大堆;反之则为最小堆[^1]。 ### 堆的操作 对于堆而言,基本操作包括插入新元素、删除任意位置上的元素以及调整堆使得其满足定义条件等。这些操作通常可以在 O(log n) 的时间复杂度下完成。当向堆中添加一个新的键值时,会先将其放置于最底层的第一个可用位置处,随后通过比较并交换该结点与其双亲直到整个序列重新成为合法的堆为止。同样地,在移除某个特定项之后也需要执行类似的修复过程来维持原有特性不变。 ### 应用场景 #### 优先队列 基于堆可以高效地构建起支持动态更新最高/低权重项目的容器——即所谓的“优先级队列”。由于每次仅需访问顶端即可获得全局最优解,并且维护成本较低廉(增删改查均为对数级别),因此非常适合处理实时性强的任务分配场合[^3]。 #### 排序算法 借助于上述提到的数据组织形式还可以设计出一类性能优良而又易于理解掌握的方法论体系之一:“堆排序法”,这是一种不依赖额外空间资源就能达到稳定性的内部分类手段。具体做法是在初始化阶段建立初始状态下的大顶堆,接着不断取出当前剩余部分里的首位成员放到最终有序数组里去,再把剩下的继续构造成新的小规模版本重复此流程直至结束。 #### 调度机制 操作系统内核层面也广泛采用了此类抽象模型来进行进程间抢占式CPU使用权的竞争管理等工作。比如Linux kernel就实现了多种不同类型的等待队列用来协调各个线程之间的协作关系,其中不乏运用到了红黑树加链表混合体这样的高级形态作为底层支撑组件的一部分。 ```c // C语言实现最大堆的一个简单例子 #include <stdio.h> #define MAX_HEAP_SIZE 100 int heap[MAX_HEAP_SIZE]; int size = 0; void swap(int *a, int *b){ int temp = *a; *a = *b; *b = temp; } void max_heapify_up(int index){ while(index > 0 && heap[(index - 1)/2] < heap[index]){ swap(&heap[(index - 1)/2], &heap[index]); index = (index - 1)/2; } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值