Binary pointer-based heap implementation

Is it possible to implement a binary heap using pointers rather than an array? I searched on the Internet (including SO) and no answer was found.

The main problem here is that how do you track the last pointer? When you insert X into the heap, you put X in the last pointer and then bubble it up. Now where is the last pointer pointing to?

And also, what happens when you want to remove a root? You exchange the root with the last element, and then discard the new root. Now, how do you know the new “last element” that you need when you delete root again?

+4
source share
6 answers

Solution 1: Keep a pointer to the last node

In this approach, a pointer to the last node is stored, and parent pointers are required.

  • When pasting, starting from the last node, go to node, under which the new last node will be inserted. Insert a new node and remember it as the last node. Move the heap as needed.

  • When deleting, starting from the last node, go to the second last node. Delete the original last node and remember the new last node just found. Move the source last node to the location of the remote node, and then, if necessary, move it up or down.

You can go to the indicated nodes in O (log (n)) time and O (1) space. The following is a description of the algorithms, but the code is available below:

  • : node , node . ... node. , node . , sibling node ( ). ( , ), . node node.

  • : node , , . ... node. , node . , node ( ). ( , ), . node.

, :

  • : node ( node node), - node ( , node node).

  • , node, last- node.

- . - , . ( - ), , , .

2. node

node count ( node). ( -) node .

, 1, . node . ( ) 1 . node; "", "".

, node 11 (= 1011b), , (0), (1), (1).

, , node ( node node_count + 1), --node ( node node_count-1).

libuv ; . .

, . , , , , , , , - .

, libuv ( ) , .

, ​​Linux ( ) - , , ( , libuv). , .

1 2 , ( - node), , , . , node N, highest_bit(X) 0 N (0 LSB).

  • ( 2) highest_bit(N).

  • node, ( 1): 2 * (1 + highest_bit((N-1) xor N)).

, ( ) , ( ) , .

highest_bit, . , - . , , 1, N, 1, 2N ).

, 1 , 2, , -, ​​ , 2. , , ( ) 2; 1 , .

1

, , , .

struct Node {
    Node *parent;
    Node *link[2];
};

struct Heap {
    Node *root;
    Node *last;
};

void init (Heap *h)
{
    h->root = NULL;
    h->last = NULL;
}

void insert (Heap *h, Node *node)
{
    // If the heap is empty, insert root node.
    if (h->root == NULL) {
        h->root = node;
        h->last = node;
        node->parent = NULL;
        node->link[0] = NULL;
        node->link[1] = NULL;
        return;
    }

    // We will be finding the node to insert below.

    // Start with the current last node and move up as long as the
    // parent exists and the current node is its right child.
    Node *cur = h->last;
    while (cur->parent != NULL && cur == cur->parent->link[1]) {
        cur = cur->parent;
    }

    if (cur->parent != NULL) {
        if (cur->parent->link[1] != NULL) {
            // The parent has a right child. Attach the new node to
            // the leftmost node of the parent right subtree.
            cur = cur->parent->link[1];
            while (cur->link[0] != NULL) {
                cur = cur->link[0];
            }
        } else {
            // The parent has no right child. This can only happen when
            // the last node is a right child. The new node can become
            // the right child.
            cur = cur->parent;
        }
    } else {
        // We have reached the root. The new node will be at a new level,
        // the left child of the current leftmost node.
        while (cur->link[0] != NULL) {
            cur = cur->link[0];
        }
    }

    // This is the node below which we will insert. It has either no
    // children or only a left child.
    assert(cur->link[1] == NULL);

    // Insert the new node, which becomes the new last node.
    h->last = node;
    cur->link[cur->link[0] != NULL] = node;
    node->parent = cur;
    node->link[0] = NULL;
    node->link[1] = NULL;

    // Restore the heap property.
    while (node->parent != NULL && value(node->parent) > value(node)) {
        move_one_up(h, node);
    }
}

void remove (Heap *h, Node *node)
{
    // If this is the only node left, remove it.
    if (node->parent == NULL && node->link[0] == NULL && node->link[1] == NULL) {
        h->root = NULL;
        h->last = NULL;
        return;
    }

    // Locate the node before the last node.
    Node *cur = h->last;
    while (cur->parent != NULL && cur == cur->parent->link[0]) {
        cur = cur->parent;
    }
    if (cur->parent != NULL) {
        assert(cur->parent->link[0] != NULL);
        cur = cur->parent->link[0];
    }
    while (cur->link[1] != NULL) {
        cur = cur->link[1];
    }

    // Disconnect the last node.
    assert(h->last->parent != NULL);
    h->last->parent->link[h->last == h->last->parent->link[1]] = NULL;

    if (node == h->last) {
        // Deleting last, set new last.
        h->last = cur;
    } else {
        // Not deleting last, move last to node place.
        Node *srcnode = h->last;
        replace_node(h, node, srcnode);
        // Set new last unless node=cur; in this case it stays the same.
        if (node != cur) {
            h->last = cur;
        }

        // Restore the heap property.
        if (srcnode->parent != NULL && value(srcnode) < value(srcnode->parent)) {
            do {
                move_one_up(h, srcnode);
            } while (srcnode->parent != NULL && value(srcnode) < value(srcnode->parent));
        } else {
            while (srcnode->link[0] != NULL || srcnode->link[1] != NULL) {
                bool side = srcnode->link[1] != NULL && value(srcnode->link[0]) >= value(srcnode->link[1]);
                if (value(srcnode) > value(srcnode->link[side])) {
                    move_one_up(h, srcnode->link[side]);
                } else {
                    break;
                }
            }
        }
    }
}

: move_one_up a node , replace_node node (srcnode) , node. , . , .

+5

. . - . , , - . , node.

. . , 6. + 1 . 7 "111". . , "11". . "1" , node. "1" , - "1" . 1 , , node. "1" , node node. , , . . node, "1" , node, "0".

node . , . , . , O (log N).

, node. , , node heapify. node, , , node, . node, HeapSize, HeapSize + 1. node. , O (log N).

, . . . node. . , .

, . , ...! ☺

+4

- , . . , , . , , , . ! , (, , ), , . , siftup/siftdown, / . , , , !

+1

, , , ( , ) , . , . (, ), / , , . , .

OP, / , , node . , .

Vamsi Sangam @. , :

#include <stdio.h>
#include <stdlib.h>

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);
}   

, :

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

Sift-down . , , , "" node, .

+1

, , .

- , .

, , , , - , .

, . . , , .

- , , , .

, , . , .

.


:

, . - - , (2 * node index +1 2 * node index + 2).

, , , .

, , .

0

( SO), .

, SO . ( Google .)

:

  • node , .
  • :
    • (root) (duh)
    • node (lastNode)
    • node (leftmostNode)
    • node (rightmostNode)

, node nodeToInsert. :

void insertNode(Data data) {
    Node* parentNode, nodeToInsert = new Node(data);
    if(root == NULL) { // empty tree
        parent = NULL;
        root = nodeToInsert;
        leftmostNode = root;
        rightmostNode = NULL;
    } else if(lastNode.parent == rightmostNode && lastNode.isRightChild()) { 
        // level full
        parentNode = leftmostNode;
        leftmostNode = nodeToInsert;
        parentNode->leftChild = nodeToInsert;
        rightmostNode = lastNode;
    } else if (lastNode.isLeftChild()) {
        parentNode = lastNode->parent;
        parentNode->rightChild = nodeToInsert;
    } else if(lastNode.isRightChild()) {
        parentNode = lastNode->parent->parent->rightChild;
        parentNode->leftChild = nodeToInsert;
    }
    nodeToInsert->parent = parentNode;
    lastNode = nodeToInsert;
    heapifyUp(nodeToInsert);
}

:

Data deleteNode() {
    Data result = root->data;
    if(root == NULL) throw new EmptyHeapException();
    if(lastNode == root) { // the root is the only node
        free(root);
        root = NULL;
    } else {
        Node* newRoot = lastNode;
        if(lastNode == leftmostNode) {
            newRoot->parent->leftChild = NULL;
            lastNode = rightmostNode;
            rightmostNode = rightmostNode->parent;  
        } else if(lastNode.isRightChild()) {
            newRoot->parent->rightChild = NULL;
            lastNode = newRoot->parent->leftChild;
        } else if(lastNode.isLeftChild()) {
            newRoot->parent->leftChild = NULL;
            lastNode = newRoot->parent->parent->leftChild->rightChild;
        }
        newRoot->leftChild  = root->leftChild;
        newRoot->rightChild = root->rightChild;
        newRoot->parent = NULL;
        free(root);
        root = newRoot;
        heapifyDown(root);
    }
    return result;
}

heapifyUp() heapifyDown() , , , , leftmostNode, rightmostNode lastNode .

TL DR Just use the damn array.

-2
source

All Articles