From 17fb3537a9702c43db26445bc23507fd082c5b94 Mon Sep 17 00:00:00 2001 From: Daniel Butter Date: Fri, 18 Jul 2025 17:39:57 -0400 Subject: [PATCH 1/2] Added subtree_sort to tree.hh and modified sort_sum to use it. --- core/algorithms/sort_sum.cc | 43 +++++++++++------------------- core/algorithms/sort_sum.hh | 3 ++- core/tree.hh | 53 +++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 28 deletions(-) diff --git a/core/algorithms/sort_sum.cc b/core/algorithms/sort_sum.cc index e4ff909f6e..5ec13f53ed 100644 --- a/core/algorithms/sort_sum.cc +++ b/core/algorithms/sort_sum.cc @@ -17,34 +17,24 @@ bool sort_sum::can_apply(iterator st) Algorithm::result_t sort_sum::apply(iterator& st) { - // This bubble sort is of course a disaster, but it'll have to do for now. - - result_t ret=result_t::l_no_action; - sibling_iterator one, two; - unsigned int num=tr.number_of_children(st); - for(unsigned int i=1; i #include #include +#include + /// A node in the tree, combining links to other nodes as well as the actual data. template @@ -425,6 +427,11 @@ class tree { void sort(sibling_iterator from, sibling_iterator to, bool deep=false); template void sort(sibling_iterator from, sibling_iterator to, StrictWeakOrdering comp, bool deep=false); + /// Sort the sibling subtrees using the user-supplied subtree_comp (which must take sibling_iterator args). + /// Returns true/false if a sort occurs. + template + bool subtree_sort(sibling_iterator from, sibling_iterator to, StrictWeakOrdering subtree_comp); + /// Compare two ranges of nodes (compares nodes as well as tree structure). template bool equal(const iter& one, const iter& two, const iter& three) const; @@ -2105,6 +2112,52 @@ void tree::sort(sibling_iterator from, sibling_iterator } } + +template +template +bool tree::subtree_sort(sibling_iterator from, + sibling_iterator to, + StrictWeakOrdering subtree_comp) + { + if (from == to) return false; + + // Populate a buffer with the subtrees to be sorted + // Use sibling_iterators since tree_node structure hidden outside tree.hh + std::vector buf; + buf.reserve(std::distance(from, to)); + for (auto it = from; it != to; ++it) buf.push_back(it); + + // Checks if sort is needed. + if (std::is_sorted(buf.begin(), buf.end(), subtree_comp)) return false; + + // Sort using the user-supplied subtree_comp function + std::stable_sort(buf.begin(), buf.end(), subtree_comp); + + // What nodes precede and follow the sorted range? + tree_node* prev = from.node->prev_sibling; // may be nullptr + sibling_iterator last = to; --last; // to is exclusive, last is inclusive + tree_node* next = last.node->next_sibling; // may be nullptr + + // Fix the sibling relationships + const std::size_t n = buf.size(); + for (std::size_t i = 0; i < n; ++i) + { + buf[i].node->prev_sibling = (i == 0) ? prev : buf[i - 1].node; + buf[i].node->next_sibling = (i + 1 == n) ? next : buf[i + 1].node; + } + + // Fix references from parent or siblings outside the sorted range + if (prev) prev->next_sibling = buf.front().node; + else if (buf.front().node->parent) buf.front().node->parent->first_child = buf.front().node; + + if (next) next->prev_sibling = buf.back().node; + else if (buf.back().node->parent) buf.back().node->parent->last_child = buf.back().node; + + return true; + } + + + template template bool tree::equal(const iter& one_, const iter& two, const iter& three_) const From dd5ebd3f6fd91a3c9f6598f2d6829be5e8a3f76c Mon Sep 17 00:00:00 2001 From: Daniel Butter Date: Fri, 15 Aug 2025 14:48:29 -0400 Subject: [PATCH 2/2] Improved bubble sort in sort_product. --- core/algorithms/sort_product.cc | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/core/algorithms/sort_product.cc b/core/algorithms/sort_product.cc index 69197ee88c..6c20f9ae8d 100644 --- a/core/algorithms/sort_product.cc +++ b/core/algorithms/sort_product.cc @@ -46,7 +46,7 @@ Algorithm::result_t sort_product::apply(iterator& st) // about using stable_sort, and then the tree.sort() doesn't do that, // and anyhow you would perhaps want exceptions. Let's just use a bubble // sort since how many times do we have more than 100 items in a product? - + // Revised version below uses improved bubble sort. result_t ret=result_t::l_no_action; Ex::sibling_iterator one, two; @@ -58,12 +58,22 @@ Algorithm::result_t sort_product::apply(iterator& st) // tr.print_recursive_treeform(std::cout, st); unsigned int num=tr.number_of_children(st); - for(unsigned int i=1; i 1) { one=tr.begin(st); two=one; ++two; // for(unsigned int j=i+1; j<=num; ++j) { // this loops too many times, no? - while(two!=tr.end(st)) { + + unsigned int current_pos = 1; // Current index location of `two` + unsigned int new_last_swap = 0; // Keep updating where the next last swap happens + + // Inner loop does not need to check inside [last_swap, num) because that's sorted + while(two!=tr.end(st) && current_pos < last_swap) { compare.clear(); auto es = compare.equal_subtree(one, two); if(compare.should_swap(one, es)) { @@ -82,12 +92,15 @@ Algorithm::result_t sort_product::apply(iterator& st) // std::cout << "MINUS" << std::endl; flip_sign(st->multiplier); } + new_last_swap = current_pos; ret=result_t::l_applied; } } ++one; ++two; + ++current_pos; } + last_swap = new_last_swap; } if(ret==result_t::l_no_action) {