theap.c 5.0 KB
Newer Older
dengyihao's avatar
dengyihao 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
 *
 * This program is free software: you can use, redistribute, and/or modify
 * it under the terms of the GNU Affero General Public License, version 3
 * or later ("AGPL"), as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

S
hash  
Shengliang Guan 已提交
16
#define _DEFAULT_SOURCE
dengyihao's avatar
dengyihao 已提交
17 18
#include "theap.h"

S
hash  
Shengliang Guan 已提交
19
size_t heapSize(Heap* heap) { return heap->nelts; }
dengyihao's avatar
dengyihao 已提交
20 21

Heap* heapCreate(HeapCompareFn fn) {
S
hash  
Shengliang Guan 已提交
22 23 24 25
  Heap* heap = calloc(1, sizeof(Heap));
  if (heap == NULL) {
    return NULL;
  }
dengyihao's avatar
dengyihao 已提交
26 27 28 29 30 31 32

  heap->min = NULL;
  heap->nelts = 0;
  heap->compFn = fn;
  return heap;
}

S
hash  
Shengliang Guan 已提交
33
void heapDestroy(Heap* heap) { free(heap); }
dengyihao's avatar
dengyihao 已提交
34

S
hash  
Shengliang Guan 已提交
35
HeapNode* heapMin(const Heap* heap) { return heap->min; }
dengyihao's avatar
dengyihao 已提交
36 37 38 39

/* Swap parent with child. Child moves closer to the root, parent moves away. */
static void heapNodeSwap(Heap* heap, HeapNode* parent, HeapNode* child) {
  HeapNode* sibling;
S
hash  
Shengliang Guan 已提交
40
  HeapNode  t;
dengyihao's avatar
dengyihao 已提交
41 42 43 44 45 46 47 48 49 50 51 52 53

  t = *parent;
  *parent = *child;
  *child = t;

  parent->parent = child;
  if (child->left == child) {
    child->left = parent;
    sibling = child->right;
  } else {
    child->right = parent;
    sibling = child->left;
  }
S
hash  
Shengliang Guan 已提交
54
  if (sibling != NULL) sibling->parent = child;
dengyihao's avatar
dengyihao 已提交
55

S
hash  
Shengliang Guan 已提交
56 57
  if (parent->left != NULL) parent->left->parent = parent;
  if (parent->right != NULL) parent->right->parent = parent;
dengyihao's avatar
dengyihao 已提交
58 59 60 61 62 63 64 65 66 67 68 69

  if (child->parent == NULL)
    heap->min = child;
  else if (child->parent->left == parent)
    child->parent->left = child;
  else
    child->parent->right = child;
}

void heapInsert(Heap* heap, HeapNode* newnode) {
  HeapNode** parent;
  HeapNode** child;
S
hash  
Shengliang Guan 已提交
70 71 72
  uint32_t   path;
  uint32_t   n;
  uint32_t   k;
dengyihao's avatar
dengyihao 已提交
73 74 75 76 77 78 79 80 81

  newnode->left = NULL;
  newnode->right = NULL;
  newnode->parent = NULL;

  /* Calculate the path from the root to the insertion point.  This is a min
   * heap so we always insert at the left-most free node of the bottom row.
   */
  path = 0;
S
hash  
Shengliang Guan 已提交
82
  for (k = 0, n = 1 + heap->nelts; n >= 2; k += 1, n /= 2) path = (path << 1) | (n & 1);
dengyihao's avatar
dengyihao 已提交
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108

  /* Now traverse the heap using the path we calculated in the previous step. */
  parent = child = &heap->min;
  while (k > 0) {
    parent = child;
    if (path & 1)
      child = &(*child)->right;
    else
      child = &(*child)->left;
    path >>= 1;
    k -= 1;
  }

  /* Insert the new node. */
  newnode->parent = *parent;
  *child = newnode;
  heap->nelts += 1;

  /* Walk up the tree and check at each node if the heap property holds.
   * It's a min heap so parent < child must be true.
   */
  while (newnode->parent != NULL && (heap->compFn)(newnode, newnode->parent))
    heapNodeSwap(heap, newnode->parent, newnode);
}

void heapRemove(Heap* heap, HeapNode* node) {
S
hash  
Shengliang Guan 已提交
109
  HeapNode*  smallest;
dengyihao's avatar
dengyihao 已提交
110
  HeapNode** max;
S
hash  
Shengliang Guan 已提交
111 112 113 114
  HeapNode*  child;
  uint32_t   path;
  uint32_t   k;
  uint32_t   n;
dengyihao's avatar
dengyihao 已提交
115

S
hash  
Shengliang Guan 已提交
116
  if (heap->nelts == 0) return;
dengyihao's avatar
dengyihao 已提交
117 118 119 120 121

  /* Calculate the path from the min (the root) to the max, the left-most node
   * of the bottom row.
   */
  path = 0;
S
hash  
Shengliang Guan 已提交
122
  for (k = 0, n = heap->nelts; n >= 2; k += 1, n /= 2) path = (path << 1) | (n & 1);
dengyihao's avatar
dengyihao 已提交
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175

  /* Now traverse the heap using the path we calculated in the previous step. */
  max = &heap->min;
  while (k > 0) {
    if (path & 1)
      max = &(*max)->right;
    else
      max = &(*max)->left;
    path >>= 1;
    k -= 1;
  }

  heap->nelts -= 1;

  /* Unlink the max node. */
  child = *max;
  *max = NULL;

  if (child == node) {
    /* We're removing either the max or the last node in the tree. */
    if (child == heap->min) {
      heap->min = NULL;
    }
    return;
  }

  /* Replace the to be deleted node with the max node. */
  child->left = node->left;
  child->right = node->right;
  child->parent = node->parent;

  if (child->left != NULL) {
    child->left->parent = child;
  }

  if (child->right != NULL) {
    child->right->parent = child;
  }

  if (node->parent == NULL) {
    heap->min = child;
  } else if (node->parent->left == node) {
    node->parent->left = child;
  } else {
    node->parent->right = child;
  }

  /* Walk down the subtree and check at each node if the heap property holds.
   * It's a min heap so parent < child must be true.  If the parent is bigger,
   * swap it with the smallest child.
   */
  for (;;) {
    smallest = child;
S
hash  
Shengliang Guan 已提交
176 177 178
    if (child->left != NULL && (heap->compFn)(child->left, smallest)) smallest = child->left;
    if (child->right != NULL && (heap->compFn)(child->right, smallest)) smallest = child->right;
    if (smallest == child) break;
dengyihao's avatar
dengyihao 已提交
179 180 181 182 183 184 185
    heapNodeSwap(heap, child, smallest);
  }

  /* Walk up the subtree and check that each parent is less than the node
   * this is required, because `max` node is not guaranteed to be the
   * actual maximum in tree
   */
S
hash  
Shengliang Guan 已提交
186
  while (child->parent != NULL && (heap->compFn)(child, child->parent)) heapNodeSwap(heap, child->parent, child);
dengyihao's avatar
dengyihao 已提交
187 188
}

S
hash  
Shengliang Guan 已提交
189
void heapDequeue(Heap* heap) { heapRemove(heap, heap->min); }