int binheap_insert(binheap_t *bh, void *key, size_t klen, void *value) { binomial_tree_node_t *node = calloc(1, sizeof(binomial_tree_node_t)); node->bh = bh; node->key = malloc(klen); memcpy(node->key, key, klen); node->klen = klen; node->value = value; int order = 0; binomial_tree_node_t *tree = list_shift_value(bh->trees); while (tree && tree->num_children == order) { if (HAS_PRECEDENCE(bh, node->key, node->klen, tree->key, tree->klen)) { binomial_tree_merge(node, tree); } else { binomial_tree_merge(tree, node); node = tree; } order++; tree = list_shift_value(bh->trees); } if (tree) list_unshift_value(bh->trees, tree); list_unshift_value(bh->trees, node); bh->count++; if (!bh->head) bh->head = node; else UPDATE_HEAD(bh); return 0; }
// merge two heaps in a single iteration binheap_t *binheap_merge(binheap_t *bh1, binheap_t *bh2) { if (bh1->mode != bh2->mode) { // refuse to merge binomial heaps initialized with different operational modes // TODO - error message return NULL; } linked_list_t *new_list = list_create(); binomial_tree_node_t *node1 = list_shift_value(bh1->trees); binomial_tree_node_t *node2 = list_shift_value(bh2->trees); binomial_tree_node_t *carry = NULL; while (node1 || node2 || carry) { if (carry) { // if we have a carry (merged tree from previous iteration) // lets check if either node1 or node2 is of the same order and // in case let's merge it before comparing node1 with node2 so // we get rid of the carry as soon as possible binomial_tree_node_t *node = NULL; if (node1 && node1->num_children == carry->num_children) { node = node1; } else if (node2 && node2->num_children == carry->num_children) { node = node2; } else { if (!node1 && !node2) { // if we have the carry but there is neither node1 nor node2 // we can just add the carry to the list and forget about it list_push_value(new_list, carry); carry = NULL; continue; } // if either node1 or node2 is of an higher order than the carry, // let's swap it so that we will always compare the lower order trees // among the three (node1, node2 and carry) if (node1 && node1->num_children > carry->num_children) { binomial_tree_node_t *tmp = node1; node1 = carry; carry = tmp; } else if (node2 && node2->num_children > carry->num_children) { binomial_tree_node_t *tmp = node2; node2 = carry; carry = tmp; } } if (node) { if (HAS_PRECEDENCE(bh1, node->key, node->klen, carry->key, carry->klen)) { binomial_tree_merge(node, carry); } else { binomial_tree_merge(carry, node); if (node == node1) node1 = carry; else node2 = carry; } carry = NULL; } } // we have already taken care of the carry here // so now if either node1 or node2 is missing // we can just add the other to the list and go ahead if (node1 && !node2) { list_push_value(new_list, node1); node1 = list_shift_value(bh1->trees); continue; } else if (node2 && !node1) { list_push_value(new_list, node2); node2 = list_shift_value(bh2->trees); continue; } else if (carry && !node1 && !node2) { // XXX - this case should have already been handled earlier // (we have a carry but neither node1 nor node2) list_push_value(new_list, carry); carry = NULL; continue; } int order1 = node1->num_children; int order2 = node2->num_children; // compare node1 and node2 and if they are of different orders // let's add the lower one to the list and go ahead if (order1 < order2) { list_push_value(new_list, node1); node1 = list_shift_value(bh1->trees); continue; } else if (order1 > order2) { list_push_value(new_list, node2); node2 = list_shift_value(bh2->trees); continue; } // if we are here node1 and node2 have the same order so they // need to be merged if (HAS_PRECEDENCE(bh1, node1->key, node1->klen, node2->key, node2->klen)) { binomial_tree_merge(node1, node2); if (carry) { if (bh1->cbs->cmp(node1->key, node1->klen, carry->key, carry->klen) >= 0) { binomial_tree_merge(node1, carry); carry = node1; } else { binomial_tree_merge(carry, node1); } } else { carry = node1; } } else { binomial_tree_merge(node2, node1); if (carry) { if (HAS_PRECEDENCE(bh1, node2->key, node2->klen, carry->key, carry->klen)) { binomial_tree_merge(node2, carry); carry = node2; } else { binomial_tree_merge(carry, node2); } } else { carry = node2; } } // the two trees (node1 and node2) have been merged and put into carry, // so let's get the next two nodes (if any) and go ahead node1 = list_shift_value(bh1->trees); node2 = list_shift_value(bh2->trees); } binheap_t *merged_heap = calloc(1, sizeof(binheap_t)); merged_heap->mode = bh1->mode; merged_heap->trees = new_list; merged_heap->count = bh1->count + bh2->count; merged_heap->cbs = bh1->cbs; return merged_heap; }
tagged_value_t * shift_tagged_value(linked_list_t *list) { return (tagged_value_t *)list_shift_value(list); }