/*!the insertion sort * * <pre> * old: 5 2 6 2 8 6 1 * * (hole) * step1: ((5)) 2 6 2 8 6 1 * (next) <= * * (hole) * step2: ((2)) (5) 6 2 8 6 1 * (next) <= * * (hole) * step3: 2 5 ((6)) 2 8 6 1 * (next) <= * * (hole) * step4: 2 ((2)) (5) (6) 8 6 1 * (next) <= * * (hole) * step5: 2 2 5 6 ((8)) 6 1 * (next) <= * * (hole) * step6: 2 2 5 6 ((6)) (8) 1 * (next) <= * * (hole) * step7: ((1)) (2) (2) (5) (6) (6) (8) * (next) * </pre> */ tb_void_t tb_insert_sort(tb_iterator_ref_t iterator, tb_size_t head, tb_size_t tail, tb_iterator_comp_t comp) { // check tb_assert_and_check_return(iterator); tb_assert_and_check_return((tb_iterator_mode(iterator) & TB_ITERATOR_MODE_FORWARD)); tb_assert_and_check_return((tb_iterator_mode(iterator) & TB_ITERATOR_MODE_REVERSE)); tb_check_return(head != tail); // init tb_size_t step = tb_iterator_step(iterator); tb_pointer_t temp = step > sizeof(tb_pointer_t)? tb_malloc(step) : tb_null; tb_assert_and_check_return(step <= sizeof(tb_pointer_t) || temp); // the comparer if (!comp) comp = tb_iterator_comp; // sort tb_size_t last, next; for (next = tb_iterator_next(iterator, head); next != tail; next = tb_iterator_next(iterator, next)) { // save next if (step <= sizeof(tb_pointer_t)) temp = tb_iterator_item(iterator, next); else tb_memcpy(temp, tb_iterator_item(iterator, next), step); // look for hole and move elements[hole, next - 1] => [hole + 1, next] for (last = next; last != head && (last = tb_iterator_prev(iterator, last), comp(iterator, temp, tb_iterator_item(iterator, last)) < 0); next = last) tb_iterator_copy(iterator, next, tb_iterator_item(iterator, last)); // item => hole tb_iterator_copy(iterator, next, temp); } // free if (temp && step > sizeof(tb_pointer_t)) tb_free(temp); }
static __tb_inline__ tb_void_t tb_heap_push(tb_iterator_ref_t iterator, tb_size_t head, tb_size_t hole, tb_size_t top, tb_cpointer_t item, tb_iterator_comp_t comp) { // check tb_assert_and_check_return(comp); // (hole - 1) / 2: the parent node of the hole // finds the final hole tb_size_t parent = 0; tb_cpointer_t parent_item = tb_null; for (parent = (hole - 1) >> 1; hole > top && (comp(iterator, (parent_item = tb_iterator_item(iterator, head + parent)), item) < 0); parent = (hole - 1) >> 1) { // move item: parent => hole // tb_iterator_copy(iterator, head + parent, item); tb_iterator_copy(iterator, head + hole, parent_item); // move node: hole => parent hole = parent; } // copy item tb_iterator_copy(iterator, head + hole, item); }
/*! adjust heap * * <pre> * init: * 16(head) * ------------------------- * | | * (hole) 10 * -------------- ------------- * | | | | * 8(larger) 7 9 3 * --------- ---- * | | | * 2 4 1(tail - 1) * * after: * 16(head) * ------------------------- * | | * 8 10 * -------------- ------------- * | | | | * (hole) 7 9 3 * --------- ---- * | | | * 2 (larger)4 1(tail - 1) * * after: * 16(head) * ------------------------- * | | * 8 10 * -------------- ------------- * | | | | * 4 7 9 3 * --------- ---- * | | | * 2 (hole) 1(tail - 1) * * </pre> */ static __tb_inline__ tb_void_t tb_heap_adjust(tb_iterator_ref_t iterator, tb_size_t head, tb_size_t hole, tb_size_t tail, tb_cpointer_t item, tb_iterator_comp_t comp) { // the comparer if (!comp) comp = tb_iterator_comp; #if 0 // save top position tb_size_t top = hole; // 2 * hole + 2: the right child node of hole tb_size_t child = (hole << 1) + 2; for (; child < tail; child = (child << 1) + 2) { // the larger child node if (comp(iterator, tb_iterator_item(iterator, head + child), tb_iterator_item(iterator, head + child - 1)) < 0) child--; // the larger child node => hole tb_iterator_copy(iterator, head + hole, tb_iterator_item(iterator, head + child)); // move the hole down to it's larger child node hole = child; } // no right child node? if (child == tail) { // the last child => hole tb_iterator_copy(iterator, head + hole, tb_iterator_item(iterator, head + tail - 1)); // move hole down to tail hole = tail - 1; } // push item into the hole tb_heap_push(iterator, head, hole, top, item, comp); #else // walk, 2 * hole + 1: the left child node of hole tb_size_t child = (hole << 1) + 1; tb_cpointer_t child_item = tb_null; tb_cpointer_t child_item_r = tb_null; for (; child < tail; child = (child << 1) + 1) { // the larger child node child_item = tb_iterator_item(iterator, head + child); if (child + 1 < tail && comp(iterator, child_item, (child_item_r = tb_iterator_item(iterator, head + child + 1))) < 0) { child++; child_item = child_item_r; } // end? if (comp(iterator, child_item, item) < 0) break; // the larger child node => hole tb_iterator_copy(iterator, head + hole, child_item); // move the hole down to it's larger child node hole = child; } // copy item tb_iterator_copy(iterator, head + hole, item); #endif }