Analysis of Correctness and Time Efficiency of HeapPermute Algorithm

The exercises in the algorithm class require analyzing the correctness of the HeapPermute algorithm, which is really strenuous, and it has taken several hours. I read the blogs of the seniors/sisters of the 11th and 12th grades. I personally think that the proof is wrong, so I compiled a version by myself (the differences are listed after the analysis of the correctness of the algorithm). Because the proof of the correctness of the algorithm is too troublesome, some steps are omitted, Wang Haihan.

0. Exercises

HeapPermute(n)
//Implement the Heap algorithm for generating permutations
//Input: a positive integer n and a global array A[1...n] (note that n is a positive integer, not a positive integer, and this question has been wrong for nearly 10 years Also drunk)
//Output: full arrangement of elements in A
if n = 1 (1)
 write A (2)
else          (3)
 for i ← 1 to n do    (4)
  HeapPermute(n − 1) (5)
 if n is odd (6)
  swap A[1] and A[n] (7)
 else swap A[i] and A[n] (8)

Note: The full arrangement is the arrangement order of all elements in the array (each element is different), such as A=[1,2,3], the full arrangement is [1,2,3], [1,3,2] ], [2,1,3], [2,3,1],[3,1,2], [3,2,1]. The result and order are also processed by the HeapPermute(3) algorithm to process the array A=[ 1,2,3] the output results and their order.

For the convenience of writing and reading, "HeapPermute" is abbreviated as "HP" in the following analysis.

1. Algorithm correctness analysis

Let the global array AAThe length of A isn (n is a positive integer) n (n is a positive integer)n ( n is a positive integer ) . After analysis, the following conclusions to be proved can be obtained:

Let kkk is a positive integer andk ≤ nk \le nkn . After executing the algorithm HP(kkk ), outputAAA formerkkAfter the full permutation of k bits ( n − k ) (nk)(nk ) combination of bits. In particular, whenk = nk = nk=When n , the output isAAThe full permutation of A. Execute the algorithm HP( kkk ) before and after, whenkkWhen k is an odd number, AAA remains unchanged; whennnWhen n is even,AAA 's ex-kkK bits rotate right one bit.
It is easy to see that the execution algorithm HP(nnn ) can output global arrayA = [ 1.. n ] A=[1 .. n]A=The full permutation of [ 1 . . n ] is a special case of conclusion ①. Therefore, it is only necessary to prove the conclusion ①.

The following uses mathematical induction to analyze and prove the conclusion ①. Suppose the global array A = [ a 1 , a 2 , ⋯ , an ] A=[a_1, a_2, \cdots, a_n]A=[a1,a2,,an], n n n is a positive integer.
  (1) Whenk = 1 k = 1k=1 , execute HP(kkk ), the output[ a 1 , a 2 , ⋯ , an ] [a_1, a_2, \cdots, a_n][a1,a2,,an] This isAAA No.1 11 -bit full permutation andAAAfter A ( n − 1 ) (n-1)(n1 ) positional combination,A = [ a 1 , a 2 , ⋯ , an ] A = [a_1, a_2, \cdots, a_n]A=[a1,a2,,an] , remains unchanged, consistent with the conclusion;
  (2) Whenk = 2 k = 2k=2k ≤ nk \le nkWhen n , execute HP(kkk ) after, exported[ a 1 , a 2 , a 3 , ⋯ , an ] [a_1, a_2, a_3, \cdots, a_n][a1,a2,a3,,an] [ a 2 , a 1 , a 3 , ⋯   , a n ] [a_2, a_1, a_3, \cdots, a_n] [a2,a1,a3,,an] , isAAA Front2 22 -bit full permutation andAAAfter A n − 2 n-2nBinary combination,A = [ a 2 , a 1 , a 3 , ⋯ , an ] A = [a_2, a_1, a_3, \cdots, a_n]A=[a2,a1,a3,,an] andAAA 's ex-kkThe k -bit is cyclically shifted to the right by one bit, which is consistent with the conclusion;
  (3) Supposek = 2 m − 1 (m is a positive integer) k = 2m -1 (m is a positive integer)k=2 m1 ( m is a positive integer ) andk < nk < nk<When n , execute HP(kkk ), outputAAA formerkkAfter the full permutation of k bits ( n − k ) (nk)(nk ) combination of bits, andAAA remains constant. Whenk = 2 mk = 2mk=2 m , the algorithm directly enters the fourth row. Fori = 1 , 2 , ⋯ , 2 mi = 1,2,\cdots,2mi=1,2,,2 m , respectively outputAAFront of A ( 2 m − 1 ) (2m-1)( 2 m1 ) Full permutation of bits andAAAfter A ( n − 2 m + 1 ) (n-2m+1)(n2 m+1 ) combination of bits, enter line 6, due tonnn is an even number,AAA 'siii bit andk = 2 mk=2mk=2 m bit interchange. The abovei = 1 , 2 , ⋯ , 2 mi=1, 2, \cdots, 2mi=1,2,,2 m for all operations, only changing the originalAAThe first k of A = 2 mk=2mk=2 m bits, just outputAAFront of A ( 2 m − 1 ) (2m-1)( 2 m1 ) full arrangement of elements andAAAfter A ( n − 2 m + 1 ) (n-2m+1)(n2 m+1 ) A combination of bits, and then in turnAAA 's first, 2 , ⋯ , 2 m 1,2,\cdots,2m1,2,,The 2 m digits are swapped to the2 mth 2m2 m bits. It is easy to see that AAis obtained through the above operationA 's ex-kkAfter the full permutation of k bits ( n − k ) (nk)(nk ) combination of bits, andAAA 's ex-kkK -bit cyclically shifts one bit to the right. Consistent with the conclusion;
  (4) Supposek = 2 m (m is a positive integer) k = 2m (m is a positive integer)k=2 m ( m is a positive integer ) andk < nk < nk<When n , execute HP(kkk ), outputAAA formerkkAfter the full permutation of k bits ( n − k ) (nk)(nk ) combination of bits, andAAA 's ex-kkK bits are cyclically shifted one bit to the right. Similar to (3), it can be proved that whenk = 2 m + 1 k = 2m+1k=2 m+1 , the algorithm HP(kkThe execution result of k ) is consistent with the conclusion.
  Therefore, the conclusion is proved.

Note: point of divergence

I personally think that the mistakes in the proofs of the previous seniors/sisters lie in the assumption that HP( nnn ) and array A (of lengthnn ), instead of HP(kkk ) is related to the array A. herennn is the array AAas the title saysThe length of A ,kkk is a positive integer andk ≤ nk \le nkn . If the assumed HP(nnn ) and the arrayAAThe relationship of A cannot be directly proved by mathematical induction on the original logic. The reason is that the second step of the proof is wrong. Suppose HP(n − 1 n-1n1 ) For arrayAAA (of length( n − 1 ) (n-1)(n1 ) ) operation satisfies the conclusion, which means that HP(n − 1 n-1n1 ) for pairs of length(n − 1) (n-1)(n1 ) arrays are valid, while proving that HP(nnn ) for array A(nnThe premise that the operation of n ) meets the needs of the conclusion is that HP(n − 1 n-1n1 ) pairs of lengthnnAn array of n is valid (the specific effect is described in the conclusion at the beginning of this section). Welcome to discuss~

2. Algorithm time efficiency analysis

The time efficiency analysis of the algorithm is considered separately for the two operations of output permutation and exchange.
  (1) Only consider the time-consuming output permutation, since the algorithm itself outputs a length of nnarrayAA of nThe full arrangement of A , so the algorithm complexityT 1 ( n ) = n ! T_1(n)=n!T1(n)=n ! ;
  (2) Considering only the time-consuming exchange operation, the following recursive expression of algorithm complexity can be obtained:
T 2 ( n ) = { 0 , ifn = 1 n + T 2 ( n − 1 ) , ifn ≥ 2 T_2(n) = \begin{cases} 0, & {\rm if} n =1\\ n + T_2(n-1), & {\rm if} n \ge 2 \end{cases}T2(n)={ 0,n+T2(n1),ifn=1ifn2
Derivation can get T 2 ( n ) = n ! + O ( nn − 1 ) T_2(n)=n! + O(n^{n-1})T2(n)=n!+O ( nn 1 ). Since whennnWhen n is a positive integer, n ! ≥ nn − 1 n! \ge n^{n-1}n!nn 1 always holds. Therefore, by
O ( f ( n ) ) + O ( g ( n ) ) = O ( max { f ( n ) , g ( n ) } ) , O(f(n)) + O(g(n)) = O(max\{ f(n), g(n)\}),O(f(n))+O(g(n))=O(max{ f(n),g ( n ) } ) ,
the algorithm complexity isT 2 ( n ) = O ( nn − 1 ) T_2(n) = O(n^{n-1})T2(n)=O ( nn1)

3. Python code

(1) Concise version code

# -*- coding: utf-8 -*-
"""
Created on Thu Apr  9 21:27:14 2020

@author: AbaloneVH
"""

import numpy as np

def swap(x, y):
  return y, x

def HP(n, A):
  if n == 1:
    print(A)
    return A
  else:
    for i in range(n):
      A = HP(n-1, A)
      if n%2 == 1:
        A[0], A[n-1] = swap(A[0], A[n-1])
      else:
        A[i], A[n-1] = swap(A[i], A[n-1])
    return A


N = 5 # 数列长度, 可调
A = np.arange(1,N+1)
A = HP(len(A), A)

(2) Code for testing

# -*- coding: utf-8 -*-
"""
Created on Thu Apr  9 21:27:14 2020

@author: AbaloneVH
"""

import numpy as np

def swap(x, y):
  return y, x

def HP(n, A, sum1, sum2):
    # sum1: 输出排列的次数
    # sum2: 交换的次数
  if n == 1:
    print(A)
    sum1 += 1
    return A, sum1, sum2
  else:
    for i in range(n):
      A, sum1, sum2 = HP(n-1, A, sum1, sum2)
      if n%2 == 1:
        A[0], A[n-1] = swap(A[0], A[n-1])
        sum2 += 1
      else:
        A[i], A[n-1] = swap(A[i], A[n-1])
        sum2 += 1
    return A, sum1, sum2


N = 5 # 数列长度, 可调
A = np.arange(1,N+1)
A, sum1, sum2 = HP(len(A), A, 0, 0)

Guess you like

Origin blog.csdn.net/AbaloneVH/article/details/105443942