Is it possible to make efficient pointer-based binary heap implementations?

前端 未结 6 1880
无人共我
无人共我 2020-12-14 12:22

Is it even possible to implement a binary heap using pointers rather than an array? I have searched around the internet (including SO) and no answer can be found.

T

6条回答
  •  难免孤独
    2020-12-14 12:47

    For those saying this is a useless exercise, there are a couple of (admittedly rare) use cases where a pointer-based solution is better. If the max size of the heap is unknown, then an array implementation will need to stop-and-copy into fresh storage when the array fills. In a system (e.g. embedded) where there are fixed response time constraints and/or where free memory exists, but not a big enough contiguous block, this may be not be acceptable. The pointer tree lets you allocate incrementally in small, fixed-size chunks, so it doesn't have these problems.

    To answer the OP's question, parent pointers and/or elaborate tracking aren't necessary to determine where to insert the next node or find the current last one. You only need the bits in the binary rep of the heap's size to determine the left and right child pointers to follow.

    Edit Just saw Vamsi Sangam@'s explanation of this algorithm. Nonetheless, here's a demo in code:

    #include 
    #include 
    
    typedef struct node_s {
      struct node_s *lft, *rgt;
      int data;
    } NODE;
    
    typedef struct heap_s {
      NODE *root;
      size_t size;
    } HEAP;
    
    // Add a new node at the last position of a complete binary tree.
    void add(HEAP *heap, NODE *node) {
      size_t mask = 0;
      size_t size = ++heap->size;
      // Initialize the mask to the high-order 1 of the size.
      for (size_t x = size; x; x &= x - 1) mask = x;
      NODE **pp = &heap->root;
      // Advance pp right or left depending on size bits.
      while (mask >>= 1) pp = (size & mask) ? &(*pp)->rgt : &(*pp)->lft;
      *pp = node;
    }   
    
    void print(NODE *p, int indent) {
      if (!p) return;
      for (int i = 0; i < indent; i++) printf(" ");
      printf("%d\n", p->data);
      print(p->lft, indent + 1);
      print(p->rgt, indent + 1);
    }   
    
    int main(void) {
      HEAP h[1] = { NULL, 0 };
      for (int i = 0; i < 16; i++) {
        NODE *p = malloc(sizeof *p);
        p->lft = p->rgt = NULL;
        p->data = i;
        add(h, p);
      }   
      print(h->root, 0);
    }   
    

    As you'd hope, it prints:

    0
     1
      3
       7
        15
       8
      4
       9
       10
     2
      5
       11
       12
      6
       13
       14
    

    Sift-down can use the same kind of iteration. It's also possible to implement the sift-up without parent pointers using either recursion or an explicit stack to "save" the nodes in the path from root to the node to be sifted.

提交回复
热议问题