📜  壳排序算法

📅  最后修改于: 2020-09-28 02:48:19             🧑  作者: Mango

在本教程中,您将学习shell排序的工作方式。此外,您还将找到使用C,C++,Java和Python进行shell排序的工作示例。

壳排序是一种算法,该算法首先对彼此远离的元素进行排序,然后依次减小要排序的元素之间的间隔。它是插入排序的通用版本。

在外壳排序中,将按特定间隔对元素进行排序。元素之间的间隔根据使用的顺序逐渐减小。 shell排序的性能取决于给定输入数组使用的序列类型。

使用的一些最佳顺序是:

  • Shell的原始序列: N/2 , N/4 , …, 1
  • Knuth的增量:1,4,13 1, 4, 13, …, (3k – 1) / 2
  • Sedgewick的增量: 1, 8, 23, 77, 281, 1073, 4193, 16577...4j+1+ 3·2j+ 1
  • 希伯德的增量:1、3、7、15、31、63、127、255、511 1, 3, 7, 15, 31, 63, 127, 255, 511…
  • Papernov和Stasevich增量:1、3、5、9、17、33、65 1, 3, 5, 9, 17, 33, 65,...
  • 普拉特(Pratt): 1, 2, 3, 4, 6, 9, 8, 12, 18, 27, 16, 24, 36, 54, 81....

Shell Sort如何工作?

  1. 假设我们需要对以下数组进行排序。
    Shell sort step
    初始数组
  2. 我们在算法中使用了外壳的原始序列(N/2, N/4, ...1 )作为间隔。

    在第一个循环中,如果数组大小为N = 8 ,则对间隔为N/2 = 4的元素进行比较并交换(如果顺序不正确)。

    1. 将第0个元素与第4个元素进行比较。
    2. 如果第0个元素大于 4个元素,则第4个元素首先存储在temp变量中,第0th元素(即,更大的元素)存储在第4th位置,而存储在temp的元素存储在0th位置。
      Shell Sort step
      以n / 2间隔重新排列元素

      对于所有其余元素,此过程将继续进行。

      Shell Sort steps
      以n / 2间隔重新排列所有元素
  3. 在第二个循环中,采用N/4 = 8/4 = 2的间隔,并再次对位于这些间隔的元素进行排序。
    Shell Sort step
    以n / 4间隔重新排列元素

    此时您可能会感到困惑。

    Shell Sort step
    比较当前间隔中数组中的所有元素。

    比较第4位2nd位的元素。还比较了0th 2位0th位的元素。比较当前间隔中数组中的所有元素。

  4. 其余元素的处理相同。
    Shell Sort step
    以n / 4间隔重新排列所有元素
  5. 最后,当间隔为N/8 = 8/8 =1时,将对间隔为N/8 = 8/8 =1的数组元素进行排序。现在,该数组已完全排序。
    Shell Sort step
    以n / 8间隔重新排列元素

壳排序算法

shellSort(array, size)
  for interval i 

Python,Java和C / C++示例

Python
爪哇
C
C++
# Shell sort in python


def shellSort(array, n):

    # Rearrange elements at each n/2, n/4, n/8, ... intervals
    interval = n // 2
    while interval > 0:
        for i in range(interval, n):
            temp = array[i]
            j = i
            while j >= interval and array[j - interval] > temp:
                array[j] = array[j - interval]
                j -= interval

            array[j] = temp
        interval //= 2


data = [9, 8, 3, 7, 5, 6, 4, 1]
size = len(data)
shellSort(data, size)
print('Sorted Array in Ascending Order:')
print(data)
// Shell sort in Java programming

import java.util.Arrays;

// Shell sort
class ShellSort {

  // Rearrange elements at each n/2, n/4, n/8, ... intervals
  void shellSort(int array[], int n) {
  for (int interval = n / 2; interval > 0; interval /= 2) {
    for (int i = interval; i < n; i += 1) {
    int temp = array[i];
    int j;
    for (j = i; j >= interval && array[j - interval] > temp; j -= interval) {
      array[j] = array[j - interval];
    }
    array[j] = temp;
    }
  }
  }

  // Driver code
  public static void main(String args[]) {
  int[] data = { 9, 8, 3, 7, 5, 6, 4, 1 };
  int size = data.length;
  ShellSort ss = new ShellSort();
  ss.shellSort(data, size);
  System.out.println("Sorted Array in Ascending Order: ");
  System.out.println(Arrays.toString(data));
  }
}
// Shell Sort in C programming

#include 

// Shell sort
void shellSort(int array[], int n) {
  // Rearrange elements at each n/2, n/4, n/8, ... intervals
  for (int interval = n / 2; interval > 0; interval /= 2) {
    for (int i = interval; i < n; i += 1) {
      int temp = array[i];
      int j;
      for (j = i; j >= interval && array[j - interval] > temp; j -= interval) {
        array[j] = array[j - interval];
      }
      array[j] = temp;
    }
  }
}

// Print an array
void printArray(int array[], int size) {
  for (int i = 0; i < size; ++i) {
    printf("%d  ", array[i]);
  }
  printf("\n");
}

// Driver code
int main() {
  int data[] = {9, 8, 3, 7, 5, 6, 4, 1};
  int size = sizeof(data) / sizeof(data[0]);
  shellSort(data, size);
  printf("Sorted array: \n");
  printArray(data, size);
}
// Shell Sort in C++ programming

#include 
using namespace std;

// Shell sort
void shellSort(int array[], int n) {
  // Rearrange elements at each n/2, n/4, n/8, ... intervals
  for (int interval = n / 2; interval > 0; interval /= 2) {
    for (int i = interval; i < n; i += 1) {
      int temp = array[i];
      int j;
      for (j = i; j >= interval && array[j - interval] > temp; j -= interval) {
        array[j] = array[j - interval];
      }
      array[j] = temp;
    }
  }
}

// Print an array
void printArray(int array[], int size) {
  int i;
  for (i = 0; i < size; i++)
    cout << array[i] << " ";
  cout << endl;
}

// Driver code
int main() {
  int data[] = {9, 8, 3, 7, 5, 6, 4, 1};
  int size = sizeof(data) / sizeof(data[0]);
  shellSort(data, size);
  cout << "Sorted array: \n";
  printArray(data, size);
}

复杂

Shell排序是一种不稳定的排序算法,因为该算法不会检查间隔之间的元素。

时间复杂度

  • 最坏情况下的复杂度 :小于或等于O(n 2 )
    外壳排序的最坏情况复杂度始终小于或等于O(n 2 )

    根据Poonen定理,壳排序的最坏情况复杂度为Θ(Nlog N) 2 /(log log N) 2 )Θ(Nlog N) 2 /log log N)Θ(N(log N) 2 )或类似的值在两者之间。

  • 最佳案例复杂度O(n*log n)
    对数组进行排序后,每个时间间隔(或增量)的比较总数等于数组的大小。
  • 平均案例复杂度O(n*log n)
    大约是O(n 1.25 )

复杂程度取决于选择的时间间隔。对于选择的不同增量序列,上述复杂度有所不同。最佳递增顺序未知。

空间复杂度:

外壳排序的空间复杂度为O(1)


壳牌分类应用

在以下情况下使用Shell排序:

  • 调用堆栈是开销。 uClibc库使用这种排序。
  • 递归超出限制。 bzip2压缩器使用它。
  • 当接近的元素相距很远时,插入排序的效果不佳。壳排序有助于缩短封闭元素之间的距离。因此,将执行的交换次数将更少。