Combined algorithm site: http://community.9cbs.net/expert/topic/3143/3143703.xml? Temp = .5916101
Author: cxjddd (airborne unrooted)
brief introduction:
This paper tells an algorithm for the "combination" in which to arrange the combination of arrangement. This algorithm is selected from the order of the combined elements and the order between elements that are not selected to facilitate the next combination - larger or smaller. The algorithm uses a similar expression method in STL (Next, Prev) Permutation, incorporating all combinations into a linear sequence of "small to large".
Keywords:
Combined human glyph algorithm STL arrangement
text:
Affected by the STL algorithm (Next_Permutation and Prev_Permutation), I want to write a combination of algorithms, and the result is an algorithm similar to the "person" word. If the word "people", all the elements are processed into the left ascending, and the right side is designed.
Let's talk about the order between combinations, two as an example of {1, 2, 3, 4}, the most "small" combination is: {1, 2}, then {1, 3}, {1, 4 }, {2, 3}, {2, 4}, the most "big" combination is {3,4}. If it is a smaller to a large list, you can quickly obtain the next larger combination quickly from the remaining elements. For example, for the combination {1, 2}, 3 can be selected from the remaining 3, 4 to replace 2, and the next combination is {1, 3}. For combination {2, 4}, 3 can be selected from the remaining 1, 3 instead of 4 to obtain the previous combination {2, 3}.
Data representation: Removal of the left section to be turned to the right, the set of elements is represented by the input interval [first, last), and the selected element is selected in the interval [first, middle), the remaining elements are interposed in the interval [Middle, Last).
△ △ △ ◎ ◎ ◎ ● ↑ ↑ ↑ First Middle Last
"△" in the figure is the element in the combination, "◎" is the remaining element, the same.
The interval [first, middle) must be ascended; and [Middle, Last) consists of two parts: ascending order and descending, if there is no ordered order on the left, all is descending, reverse, no order, but all is ascended. Moreover, the ascending part of [first, middle) and [Middle, Last) is continuous. Zhizheng right drop, so as "human" glyph is shaped. Hereinafter referred to as the front; referred to as [Middle, Last) is the rear; and the ascending portion in the rear portion is a liter portion, the descending sequence portion is the lower portion.
◎ ◎ △ ◎ △ ◎ ◆ ◎ ◆ ■ ◎ △ ◆ △ ■ ◎ ◆ ◆ △ ◆ ◆ ■ ◎ ◎ △ ■ ◆ △ ■■ △ ◆ ◆ ■ ◆ ◆ ◎ ■ ◆ ◆ ◎ ■■ ◆ ◎ ■■ ◎ ◎ △ ■ ◆◆◆ △ ■ ◆◆ △ ■ ◆◆ ■ △ ■ ◎ △ ■■ ◆◆◆ △ ■ ◆ ◆ ◆ △ ■ ◆ ◆ ◆ ■■ ◆ ◆ ◎ ■ ■■ ◆◆ ◎ ■■■ ◆◆◆ ■■■ ◆◆◆ ■■■ ◆ ◆ ■■■ ◆◆ ■ ■ ◆◆◆ ■■ ◆◆◆ ■■■ ◆◆◆ ■■■ ◆◆ ↑↑ ↓ ↓ ↑ ↑ ↓↓ a e b e be be be be be be
"↑" in the figure indicates that the element belongs to the liter, "↓" belongs to the bottom. The last element of the front is B, and all the elements of all liters are not less than * b, and all elements that belong to the lower portion are less than * b.
According to this feature, you can write a normalized function Adjust_combination (): first sort the elements of the front and rear portions, and then folded with * B as "axis" in * b in the back element. The code is approximately as follows:
// Standardize Adjust_Combination (First, Middle, Last) {sort_combination (first, middle); sort_combination (middle, last);
J = LOWER_BOUND (Middle, Last, * B); / * At this time [Middle, J) is an element of the lower portion, and [J, Last) is an elements of the liter * /
Reverse (J, Last); // Reverse [J, Last) reverse Reverse (Middle, Last); // Reverse [Middle, Last) reversal / * liter or ascended, adjust to the left; * fill It is descending order and adjusts to the right. * /}
There are two STL functions (algorithms) in this algorithm, in realization. Such a function probably has the following:
iter_swap (i, j): Switch between two iterator points to space * i and * j;
Reverse (f, l): Reverse, adjust the elements in [F, L) before and after
INPLACE_MERGE (F, M, L): merge, combine two ordered intervals [F, M) and [M, L) into an ordered interval [F, L);
Lower_Bound (f, l, v): Find the first position of the first not less than V in the ordered interval [F, L);
Upper_bound (f, l, v): Find the first position larger than V in the ordered interval [F, L).
In addition to the functions of these STLs, there is a sort_combination () for sorting, which is actuated in INPLACE_MERGE (), and sorted by merged.
According to the size of the elements and * b in the rear, it can be distinguished from the liters and lowering portions in the rear portion: the maximum element in [middle, last) is E, and the first less than the element is f after E (if No, let F = Last). If * e> = * b, there must be [MIDDLE, F) is the liter, [F, Last) is a drop; the opposite is * E <* B, must have e == middle and [Middle, Last) Faded.
The following is analyzed with the conditions of "no repetitive elements, combined from small to large".
First examine such procedures, {1, 2, 3, 4, 5, 6} choose three:
For (a = 1; a <= 6-2; a ) for (b = a 1; b <= 6-1; b ) for (c = C 1; c <= 6; C ) OUT (a , B, C);
This procedure is "from a small to large", where c corresponds to the last element of the front, and the front portion of {A, B, and C} corresponds to the front. If the value of C is not the largest, find the next larger value of C. If C is already the largest value, let B become large; if B has reached the maximum value, the value of A will change. If A cannot be large, it ends. Of course, A actual maximum is 4, B is 5. If the value of A or B is changed, then the value of the subsequent elements must be changed together, as combined {1, 4} becomes {2, 3}. As can be seen from the above, the most important thing is that the elements you want to be replaced from the current combination are selected from the remaining elements, and then exchange, adjust. Simply put, it is to find the largest element that can become larger, and become bigger. This algorithm arranges such a human glyph structure, which is to facilitate two key elements.
If there is an increase in liters (* B <* e, or * b <* middle), it means that there is a larger element than * b, so the first element of the liter is selected * MIDDLE and * B swap. In addition to adjustment, you can use the "bubbling" method to move the * B.
// Presence the liter, replace * b if (* b <* e) {j = b; i = j ; while ((j! = Last) && (* i <* j)) ore_swap (i , j ) }
If there is only two cases, then there are two situations: First, * first> * e, the combination is already the biggest; it is not the biggest combination, you can ask for a bigger. One of the previous situations is simple and adjustable to the minimum combination. In the latter case, the elements to be replaced in the front are required and the elements to be selected in the lower portion are required.
// Only the bottom, and is already the largest combination IF (* e <* first) {Reverse (first, middle); Reverse (first, last);}
(In the latter case) element * i can be obtained by * middle, that is, the largest element that is less than * middle in front. Asking for an element * i to be replaced, then you can find an element * J of the replacement * J: that is, the minimum element greater than * i is larger than the minimum element. In addition to swap * i and * j, adjust the elements between I to J to adjust. It is very interesting to have been twice in this, and the front is the biggest in less than in the last, and the latter is greater than the minimum.
// Only a larger combination // to be replaced: i = b; while (! (* - i <* middle)); // Used to replace the element: J = Last; WHILE (! (* i <* - j));
/ / Exchange ITER_SWAP (I, J);
// Adjust the element of i to J REVERSE ( i, middle); // The largest element in front Reverse (i, j); // The smallest element is before
As mentioned earlier is the algorithm when "no duplicate elements, and from small to large". It can be divided into three situations: one is to exist; the other is the biggest; the third is to elect the element from the lower part. Such a next_combination that handles no duplicate elements is coming out, and you can also name it be NEXT_COMBINATION_UNIQUE (). If there is a repetitive element, then "equal to" comparison, the above three cases will be changed. It is still only compared to "less than", equal to and greater than the change from less than. The first case can be changed to * b less than * middle. The second case is to change the condition of judgment, change! (* First <* e). The rest is divided into two: one is * b <* e, indicating that there is an elements that exist than * B, and find out the elements that are larger than * B, replace * B; Then, the third similar to the repeating element, find the maximum * e small element * i from the front part, find the minimum than * i large elements * J, exchange i and j in the lower part Adjustment.
(Khan! Write to front, discover the bug on a thought, but also no problem.)
Summary "There is a repetitive element, from a small to big" code is approximately as follows:
/ * This code is not verified, and the source code is quasi-* / if (* b <* middle) {j = b; i = j ; while ((j! = Last) && (* i <* j)) iter_swap I , J ); return true;} if (! (* first <* e)) {Reverse (first, middle); Reverse (first, last); Return False;}
IF (* b <* e) {bb = b; while ( b! = e) &&! (* b <* bb)); Reverse (bb, f); Reverse (B, f); return true } Else {i = b; while (! (* - i <* e)); j = last; while (! (* I <* - j)); iter_swap (i, j); Reverse ( I, Middle); Reverse (i, j); return true;}
The algorithm from large to small is discussed below, first assumes that there is no identical element. From the large to small algorithm, simply say that the maximum can be changed, and it is smaller.
If there is no rise (* middle <* b or * e <* b), * middle (* e) is the element to be newly selected, and the element to be selected is the first ratio * e large element. This situation is the simplest.
IF (* middle <* b) {i = Upper_bound (first, middle, * middle); iter_swap (i, middle);}
If there is an increase in liter (* b <* middle), it is divided into two situations; one is f == last, indicating that only the liter is no, but also reaches the minimum combination; the other, * f is to choose new Elements, find the first element than * f, that is, the element to be elected (of course, the selected element may be more). / * Only an increase in liters, it is already a minimum combination * / if (f == last) {Reverse (first, last); Reverse (first, middle);}
In the second case, find the first element * i, * i is the element to change, and (i, middle) is replaced with all the largest elements (* b should be all elements) The largest element, then it is a small element in turn).
/ * There is also a lower portion, do a large adjustment * / i = Upper_bound (first, middle, * f); Iter_Swap (i, f); Reverse ( i, f); Reverse (i, middle);
If there is a repeating element, the main change from the large to a small algorithm is to determine whether the change in the replacement is B, performing different processing. Mainly because the existence of the same element makes the adjustment after the exchange elements become more complex, thus doing corresponding changes.
IF (* middle <* b) {i = Upper_bound (first, middle, * middle); if (i! = b) iter_swap (i, middle); else {s = middle; while (( s! = last ) &&! (* s <* middle); Reverse (B, S);} Return True;
IF (f == last) {Reverse (first, last); Reverse (first, middle); Return False;}
i = Upper_bound (first, middle, * f); if (i == b) {s = f; while (( s! = last) &&! (* s <* f)); Reverse (B, F Reverse (B, S);} else {ified_swap (i, f); Reverse ( i, f); Reverse (i, middle);} Return True;
At this point, the combination algorithm Combination has been finished, but it is relatively vague. Some things will be told in the next section, but the complete procedure is already there.
Template
Void
Sort_combination (Biiterator First, Biiterator Last)
{
IF (first == last) // $ (ac; spt * kx
(B return;
Biiterator i = first; i; if (i == last) // $ (ar; 8vt * kx (b return; int hALF = distance (first, last) / 2; // Half of the length biiterator middle = First; Advance (Middle, Half); // Middle = Halfsort_combination (first, middle); // sort first part sort_combination (middle, last); // Sort Second Part
INPLACE_MERGE (First, Middle, Last); // Merge Two Parts}
Template
Void
Adjust_combination (Biiterator First, Biiterator Middle, Biiterator Last)
{
// The Front Part Or The Back Part Have No Elements
IF ((first == middle) || (middle == last))
Return;
Sort_combination (first, middle); sort_combination (middle, last);
Biiterator B = Middle; --B; Biiterator J = Lower_Bound (Middle, Last, * B); Reverse (J, Last); Reverse (Middle, Last);}
Template
Void
Init_combination (Biiterator First, Biiterator Middle, Biiterator Last,
BOOL MIN)
{
Sort_combination (first, last);
IF (min == false) {// The max combination reverse (first, last); Reverse (first, middle);}}
Template
Bool
Next_combination (Biiterator First, Biiterator Middle, Biiterator Last)
{
IF ((first == middle) || (middle == last))
Return False;
// Last Element of [first, middle) Biiterator B = middle; --b;
IF (* B <* middle) {Biiterator J = B; While ( B! = Last) && (* j <* b)) {i_swap (j, b); j = b;} return true;}
Biiterator E = last; --e; while (e! = Middle) {Biiterator K = E; --K; if (! (* K <* e)) E = K; Else Break;} Biiterator F = E; f; while ((f! = last) &&! (* f <* e)) f; if (! (* first <* e)) {Reverse (first, middle); Reverse (First, Last Return False;}
IF (* b <* e) {Biiterator BB = B; While ( BB! = E) &&! (* B <* bb)); Reverse (bb, f); Reverse (b, f);} Else {Biiterator I = B; While (! (* - i <* e)); Biiterator J = Last; While (! (* i <* - j));
Iter_Swap (i, j); Reverse ( i, middle); Reverse (i, j);} return true;}
Template
Bool
Prev_Combination (Biiterator First, Biiterator Middle, Biiterator Last)
{
IF ((first == middle) || (middle == last))
Return False;
Biiterator b = middle;
--b;
IF (* middle <* b)
{
Biiterator I = Upper_bound (first, middle, * middle);
IF (i! = b)
iter_swap (i, middle);
Else
{
Biiterator s = middle;
While ( S! = last) &&! (* s <* middle))
;
Reverse (b, s);
}
Return true;} Biiterator E = Last; --e; while (e! = middle) {Biiterator K = E; --K; if (! (* k <* e)) E = K; Else Break;} Biiterator F = E; f; while ((f! = last) &&! (* f <* e)) f;
IF (/ *! (* E <* b) && * / (f == last)) {Reverse (first, last); Reverse (first, middle); return false;}
Biiterator I = Upper_bound (first, middle, * f); if (i == b) {Biiterator S = F; While (( S! = Last) &&! (* S <* f)); Reverse (B , f); Reverse (B, S);} else {ified_swap (i, f); Reverse ( i, f); Reverse (i, middle);} return true;}