[Speaking algorithm small class] Enumerate all permutations of n elements in ascending lexicographical order (algorithm steps + proof of correctness)

Insert picture description here

Full arrangement

definition

Take all n elements out of n elements and arrange them to get the full arrangement.

Algorithm: Enumerate all permutations of n elements in ascending lexicographical order

Suppose a full permutation of the set {a_1,a_2,...,a_n} is P=p_1,p_2,...,p_(j-1),p_j,p_(j+1),...,p_n.
[1] Starting from the right end of the arrangement, find the first number j that is smaller than the number on the right. That is: Let
i=n-1, n-2,...
When p_i<p_(i+1) is satisfied for the first time, stop, and mark j=i.
If no matching i is found, it means that the lexicographical order of the entire arrangement is the largest, and the algorithm ends.
[2] In the numbers on the right of p_j, find the smallest number p_k among all the numbers larger than p_j, that is,
p_k=min⁡〖{p_i |p_i>p_j, i=j+1,…,n}〗
k= i
If a plurality of matches occurring p_i, note the k subscript that the maximum number of index numbers for these.
[3] Exchange p_j, p_k.
[4] Reverse the descending interval at the right end of the arrangement.

prove

The following proves: when the lexicographical order of the original arrangement has not reached the maximum, the new arrangement constructed according to the above algorithm (ie the next arrangement) must be larger than the lexicographical order of the original arrangement, and the lexicographical order increment is the smallest.
The original arrangement is divided into several sub-arrangements, and each sub-arrangement is either increasing, or decreasing, or neither increasing nor decreasing. For the rightmost segment (easy to know: the length of this segment is at least 2):
(1) If the segment is incremented, it is easy to prove: after executing this algorithm once, the two numbers on the rightmost will swap positions, so the most The two numbers on the right form a descending sub-sequence. Transfer to the situation (2).
(2) If the paragraph is decreasing, the lexicographic order of this decreasing sub-arrangement is already the largest, that is to say, the lexicographic order of this sub-arrangement cannot be changed to a larger one without changing the left side of the sub-arrangement. Therefore, to construct the next arrangement, other elements must be used.
Suppose there are d elements on the left side of the rightmost segment of the sub-arrangement with the largest lexicographic order. Under the condition of "need to increase the lexicographic order of the arrangement composed of the first d elements", in order to make the increase of the lexicographic order of the entire arrangement as small as possible, it is easy to obtain: the order of the first (d-1) elements should be kept unchanged change.
In order to increase the lexicographic order of the new arrangement, only the order of the dth to the nth element can be changed, and the lexicographical order of the sub-arrangement formed by the (d+1)th to the nth element is already the largest, so the dth The element at this position must be replaced with an element larger than the original element p_d at that position.
In order to make the lexicographical increment as small as possible, the element interchanged with d should be as large as possible and smaller than d. So step [3] of the algorithm is correct.
In addition, the lexicographical order of the sub-permutations formed by the (d+1)th to nth elements should be minimized.
Easy to prove: The number on the right end found by [1] must be in descending order. After [3], the numbers at the right end are still in descending order.
Therefore, directly inverting the (d+1)th to the nth elements can minimize the lexicographic order of the arrangement they constitute. So step [4] of the algorithm is correct.
When multiple p_i are found in step [2], it is easy to prove: only by swapping p_j found in step [1] with p_i with the largest subscript can the lexicographic order of the new arrangement be minimized. Based on the above proof process, step [1] [2] of the algorithm is also correct.
(3) If the paragraph is neither increasing nor decreasing, it is easy to prove: only by swapping p_j found in step [1] with the rightmost element can the lexicographic order of the new arrangement be minimized. QED.

Processing of special data

After inspection, when there are only 1 or 2 elements participating in the enumeration, the algorithm can give the correct result and end normally.

Code

template<class _Ty> bool NextPermutation(_Ty* const _First, _Ty* const _Last) {
    
    
	static_assert(is_arithmetic<_Ty>::value, "Only arithmetic type (int, double ...) are allowed.");
	_Ty* i = nullptr, * j = nullptr, * k = nullptr;
	for (i = _Last - 2; i >= _First; --i) {
    
    
		if (*i < *(i + 1)) {
    
     j = i; break; }
	}
	if (j == nullptr) {
    
     reverse(_First, _Last); return false; }
	_Ty m = numeric_limits<_Ty>::max();
	for (i = j + 1; i < _Last; ++i) {
    
    
		if (*i > * j && *i <= m) {
    
     m = *i; k = i; }
	}
	swap(*j, *k);
	reverse(j + 1, _Last);
	return true;
}

Note: If you continue to enumerate the next permutation for the full permutation that has reached the largest lexicographical order, the permutation will be reversed to the smallest lexicographical permutation and return false. If the current lexicographic order has not reached the maximum, return true. During the execution of the algorithm, the storage content of the interval [_First, _Last) participating in the arrangement will change.

Guess you like

Origin blog.csdn.net/COFACTOR/article/details/109234849