Part 1 - Subdividing Intervals
When you restrict the number of dimensions to 1, a box is just an interval. Consider a datastructure called "check_point":
struct check_point {
float value;
bool start; // true if this is the start of an interval, false otherwise.
int id; // The id of the interval that is starting or ending at this value.
}
First convert the start and end points of the 1d interval by their values in an array. Iterate through this array, and every 2 consecutive checkpoints create a new interval.
You maintain a set of currently open interval ids while iterating through the check points. Whenever you encounter a 'start' check point, you add the id to the set, and whenever you encounter a 'end' check point, you remove the id from the set. Everytime you create a new interval, you assign the current id-set to the created interval. This looks like the picture below.
Part 2 - Subdividing Boxes
Now let's take the logic from part-1 and adapt it for higher dimensions.
First decompose the boxes into x, y and z intervals (just x and y in 2d). If you start with n boxes, you should end up with n each of x-intervals, y-intervals and z-intervals. Apply the algorithm from Part 1 separately for the set of x, y and z intervals, which should give you 3 sets of output intervals.
Now we have to convert these 1d intervals back into boxes.
For a given combination of x,y and z output intervals, you should create a box only if the intersection of the index-sets of all 3 intervals (x, y and z) is not an empty set. You ignore the xyz interval combinations that don't have indices in common. This gives you a set of subdivided boxes.
The picture below demonstrates an example in 2d. The dotted lines show all poossible combinations of x and y intervals. The combinations that are marked with 'x' are ignored because they don't have any indices in common. The combinations that get converted into boxes have a check mark in them. The same logic should also work in 3 or more dimensions.
Note: This algorithm gives you more boxes (smaller in size) than those in your example. But this is more deterministic, without following arbitrary conventions for subdividing boxes. You can always modify the algorithm to create fewer boxes depending on your exact needs. For example, you can walk the grid shown in the second image to merge boxes either along x or y or both.