问题
This is the shell sort algorithm.
  void shellSort(int array[], int n){
    for (int gap = n/2; gap > 0; gap /= 2){
        for (int i = gap; i < n; i += 1) {
           int temp = array[i];
           int j;
           for (j = i; j >= gap && array[j - gap] > temp; j -= gap){
              array[j] = array[j - gap];
           }
           array[j] = temp;
        }
      }
  }
I'm certain that the outer loop of this algorithm runs logn times but I'm not sure with the middle loop and the innermost loop. This site https://stackabuse.com/shell-sort-in-java/ said that the middle loop runs n-gap times while the innermost loop runs i/gap but I'm not so sure about that. Please help me understand how the middle and innermost loop runs in this algorithm, thank you so much for anyone helping me this.
回答1:
These are the loops in the algorithm:
for (int gap = n/2; gap > 0; gap /= 2) {
  for (int i = gap; i < n; i += 1) {
    for (j = i; j >= gap && array[j - gap] > temp; j -= gap) {
    }
  }
}
Let's start with loop over i. It starts at gap and goes to n with increment of 1. The next loop over j starts at current i and goes down by gap until it becomes smaller than gap. So, the loop over j executes once for i between gap and 2*gap, twice for i between 2*gap and 3*gap, three time for i between 3*gap and 4*gap and so on. 
That means that the j loop will execute once for gap different values of i, twice for gap different values of i, three times for gap different values of i, etc.
The maximum value for i is n, so the loop over j can execute at maximum j_max = (n - gap)/gap times. Total number of executions of the j loop is 
1+1+...+1+1 + 2+2+...+2+2 + 3+3+...+3+3 + .... + j_max+j_max+...+j_max+j_max
|_________|   |_________|   |_________|          |_________________________|
 gap times     gap times     gap times                    gap times 
This sum is equal to
gap*(sum from 1 to j_max) = gap * j_max(j_max + 1) / 2 = O(gap * ((n-gap)/gap)^2) = O((n-gap)^2/gap)
This will be repeated for different values of gap in the outer loop, so the complexity is O-big of  
sum((n-gap)^2/gap, for gap = n/2, n/4, n/8, ...., 4, 2, 1)
Expanding:
(n^2 - 2*n*gap + gap^2)/gap = n^2*(1/gap) - 2*n + gap
The first term is equal to n squared multiplied by the following values:
1/(n/2),  1/(n/4),  1/(n/8), ..... 1/4,  1/2, 1/1
or
2/n, 4/n, 8/n, ....., n/n
This is a sum of powers of two divided by n, so the first term gives in total
n^2/n * 2^(log2 n) = n^2
The second term is -2*n summed log2 n times, so complexity is 
n*log2 n
The last term is sum of gaps, so it's sum of powers of two and its complexity is n.
Combining all together we get the worst case complexity as O(n^2).
回答2:
In each iteration, the middle loop starts at gap and ends at n. So the total number of iterations would be n - gap
The inner gap starts at i. In each iteration, it gets reduced by gap. Suppose i = 15 and gap = 3, then values of j in subsequent iterations would be 15,12,9,6,3. Which is 5 iterations. Therefore i/gap iterations in the worst case.
回答3:
The formula for finding number of terms in an arithmetic sequence is (last term - first term) / difference + 1
for (int i = gap; i < n; i += 1) 
starts at i = gap and exits when i == n. Last value i can take is n - 1.
Every loop, i is incremented by 1, so this loop gets executed (n - 1 - gap) / 1 + 1 = n - gap times
for (j = i; j >= gap && array[j - gap] > temp; j -= gap)
This loop starts at j = 1 and exits when j < gap (ignore the second part by assuming worst case senario). The last value j can take is gap.
Every loop, j is decremented by gap, so this loop gets executed (i - gap)/gap + 1 = i
来源:https://stackoverflow.com/questions/60509951/analyzing-shell-sort-algorithm-big-o