排序算法

排序算法

下面是对比较类排序算法的详细介绍:

  1. 冒泡排序(Bubble Sort):

    • 原理:通过重复遍历待排序的数列,比较每对相邻元素,如果它们的顺序错误就把它们交换过来。遍历数列的工作是重复进行的,直到没有再需要交换的元素,这意味着该数列已经排序完成。

    • 时间复杂度:平均和最坏情况下都是 O(n2)O(n2),最好情况是 O(n)O(n)(当输入数组已经是有序的)。

    • 空间复杂度:O(1)O(1),因为它只需要一个额外的存储空间。

    • 代码实现:

      public class BubbleSort {
          public static void bubbleSort(int[] arr) {
              int n = arr.length;
              for (int i = 0; i < n - 1; i++) {
                  for (int j = 0; j < n - i - 1; j++) {
                      if (arr[j] > arr[j + 1]) {
                          // swap arr[j] and arr[j+1]
                          int temp = arr[j];
                          arr[j] = arr[j + 1];
                          arr[j + 1] = temp;
                      }
                  }
              }
          }
      
          public static void main(String[] args) {
              int[] arr = {64, 34, 25, 12, 22, 11, 90};
              bubbleSort(arr);
              System.out.println("Sorted array: ");
              for (int i : arr) {
                  System.out.print(i + " ");
              }
          }
      }
      
  2. 选择排序(Selection Sort):

    • 原理:首先在未排序序列中找到最小(或最大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(或最大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

    • 时间复杂度:无论最好、最坏和平均情况都是 O(n2)O(n2)。

    • 空间复杂度:O(1)O(1)。

    • 代码实现:

      public class SelectionSort {
          public static void selectionSort(int[] arr) {
              int n = arr.length;
              for (int i = 0; i < n - 1; i++) {
                  int min_idx = i;
                  for (int j = i + 1; j < n; j++) {
                      if (arr[j] < arr[min_idx]) {
                          min_idx = j;
                      }
                  }
                  // swap arr[i] and arr[min_idx]
                  int temp = arr[min_idx];
                  arr[min_idx] = arr[i];
                  arr[i] = temp;
              }
          }
      
          public static void main(String[] args) {
              int[] arr = {64, 25, 12, 22, 11};
              selectionSort(arr);
              System.out.println("Sorted array: ");
              for (int i : arr) {
                  System.out.print(i + " ");
              }
          }
      }
      
  3. 插入排序(Insertion Sort):

    • 原理:构建有序序列,对未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到 O(1)O(1) 的额外空间的排序)。

    • 时间复杂度:平均和最坏情况下都是 O(n2)O(n2),最好情况是 O(n)O(n)(当输入数组已经是有序的)。

    • 空间复杂度:O(1)O(1)。

    • 代码实现:

      public class InsertionSort {
          public static void insertionSort(int[] arr) {
              int n = arr.length;
              for (int i = 1; i < n; ++i) {
                  int key = arr[i];
                  int j = i - 1;
                  while (j >= 0 && arr[j] > key) {
                      arr[j + 1] = arr[j];
                      j = j - 1;
                  }
                  arr[j + 1] = key;
              }
          }
      
          public static void main(String[] args) {
              int[] arr = {12, 11, 13, 5, 6};
              insertionSort(arr);
              System.out.println("Sorted array: ");
              for (int i : arr) {
                  System.out.print(i + " ");
              }
          }
      }
      
  4. 希尔排序(Shell Sort):

    • 原理:也称递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因DL.Shell于1959年提出而得名。希尔排序是把记录按不同的步长分组,对每组使用直接插入排序算法排序;随着步长逐渐缩小,整个序列基本有序,最后进行一次直接插入排序算法。

    • 时间复杂度:平均情况 O(nlogn)O(nlogn) 到 O(n2)O(n2),取决于步长序列的选择。

    • 空间复杂度:O(1)O(1)。

    • 代码实现:

      public class ShellSort {
          public static void shellSort(int[] arr) {
              int n = arr.length;
              for (int gap = n / 2; gap > 0; gap /= 2) {
                  for (int i = gap; i < n; i += 1) {
                      int temp = arr[i];
                      int j;
                      for (j = i; j >= gap && arr[j - gap] > temp; j -= gap)
                          arr[j] = arr[j - gap];
                      arr[j] = temp;
                  }
              }
          }
      
          public static void main(String[] args) {
              int[] arr = {12, 34, 54, 2, 3};
              shellSort(arr);
              System.out.println("Sorted array: ");
              for (int i : arr) {
                  System.out.print(i + " ");
              }
          }
      }
      
  5. 归并排序(Merge Sort):

    • 原理:采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。

    • 时间复杂度:无论最好、最坏和平均情况都是 O(nlogn)O(nlogn)。

    • 空间复杂度:O(n)O(n),因为需要额外的空间来存储合并后的数组。

    • 代码实现:

      public class MergeSort {
          public static void mergeSort(int[] arr) {
              mergeSort(arr, 0, arr.length - 1);
          }
      
          private static void mergeSort(int[] arr, int l, int r) {
              if (l < r) {
                  int m = (l + r) / 2;
                  mergeSort(arr, l, m);
                  mergeSort(arr, m + 1, r);
                  merge(arr, l, m, r);
              }
          }
      
          private static void merge(int[] arr, int l, int m, int r) {
              int n1 = m - l + 1;
              int n2 = r - m;
              int[] L = new int[n1];
              int[] R = new int[n2];
              for (int i = 0; i < n1; ++i)
                  L[i] = arr[l + i];
              for (int j = 0; j < n2; ++j)
                  R[j] = arr[m + 1 + j];
              int i = 0, j = 0;
              int k = l;
              while (i < n1 && j < n2) {
                  if (L[i] <= R[j]) {
                      arr[k] = L[i];
                      i++;
                  } else {
                      arr[k] = R[j];
                      j++;
                  }
                  k++;
              }
              while (i < n1) {
                  arr[k] = L[i];
                  i++;
                  k++;
              }
              while (j < n2) {
                  arr[k] = R[j];
                  j++;
                  k++;
              }
          }
      
          public static void main(String[] args) {
              int[] arr = {12, 11, 13, 5, 6};
              mergeSort(arr);
              System.out.println("Sorted array: ");
              for (int i : arr) {
                  System.out.print(i + " ");
              }
          }
      }
      
  6. 快速排序(Quick Sort):

    • 原理:通过一个基准值将数据分为两部分,其中一部分的所有数据都比另外一部分的所有数据要小,然后再递归地对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以达到整个数据变成有序序列。

    • 时间复杂度:平均情况 O(nlogn)O(nlogn),最坏情况 O(n2)O(n2)(当数据已经是有序或逆序时)。

    • 空间复杂度:O(logn)O(log**n),递归栈的深度。

    • 代码实现:

      public class QuickSort {
          public static void quickSort(int[] arr, int low, int high) {
              if (low < high) {
                  int pi = partition(arr, low, high);
                  quickSort(arr, low, pi - 1);
                  quickSort(arr, pi + 1, high);
              }
          }
      
          private static int partition(int[] arr, int low, int high) {
              int pivot = arr[high];
              int i = (low - 1);
              for (int j = low; j < high; j++) {
                  if (arr[j] < pivot) {
                      i++;
                      int temp = arr[i];
                      arr[i] = arr[j];
                      arr[j] = temp;
                  }
              }
              int temp = arr[i + 1];
              arr[i + 1] = arr[high];
              arr[high] = temp;
              return i + 1;
          }
      
          public static void main(String[] args) {
              int[] arr = {10, 7, 8, 9, 1, 5};
              quickSort(arr, 0, arr.length - 1);
              System.out.println("Sorted array: ");
              for (int i : arr) {
                  System.out.print(i + " ");
              }
          }
      }
      
  7. 堆排序(Heap Sort):

    • 原理:利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子节点的键值或索引总是小于(或者大于)它的父节点。

    • 时间复杂度:无论最好、最坏和平均情况都是 O(nlogn)O(nlogn)。

    • 空间复杂度:O(1)O(1),因为堆是原地排序。

    • 代码实现:

      public class HeapSort {
          public static void heapSort(int[] arr) {
              int n = arr.length;
              for (int i = n / 2 - 1; i >= 0; i--)
                  heapify(arr, n, i);
              for (int i = n - 1; i >= 0; i--) {
                  int temp = arr[0];
                  arr[0] = arr[i];
                  arr[i] = temp;
                  heapify(arr, i, 0);
              }
          }
      
          private static void heapify(int[] arr, int n, int i) {
              int largest = i;
              int l = 2 * i + 1;
              int r = 2 * i + 2;
              if (l < n && arr[l] > arr[largest])
                  largest = l;
              if (r < n && arr[r] > arr[largest])
                  largest = r;
              if (largest != i) {
                  int swap = arr[i];
                  arr[i] = arr[largest];
                  arr[largest] = swap;
                  heapify(arr, n, largest);
              }
          }
      
          public static void main(String[] args) {
              int[] arr = {12, 11, 13, 5, 6, 7};
              heapSort(arr);
              System.out.println("Sorted array: ");
              for (int i : arr) {
                  System.out.print(i + " ");
              }
          }
      }
      

排序算法比较

排序算法 时间复杂度 (平均) 时间复杂度 (最坏) 时间复杂度 (最好) 空间复杂度 稳定性 备注
冒泡排序 O(n^2) O(n^2) O(n) O(1) 不稳定 简单但效率低
选择排序 O(n^2) O(n^2) O(n^2) O(1) 不稳定 简单但效率低
插入排序 O(n^2) O(n^2) O(n) O(1) 稳定 对小数据集或基本有序的数据集效率高
希尔排序 O(nlogn) O(n^2) O(nlogn) O(1) 不稳定 效率比简单插入排序高,但不如快速排序和归并排序
归并排序 O(nlogn) O(nlogn) O(nlogn) O(n) 稳定 高效率,需要额外空间
快速排序 O(nlogn) O(n^2) O(nlogn) O(logn) 不稳定 高效率,但最坏情况下效率低
堆排序 O(nlogn) O(nlogn) O(nlogn) O(1) 不稳定 可以原地排序,但构建堆的过程可能较慢

这些算法中,归并排序和堆排序是稳定的排序算法,而快速排序和冒泡排序、选择排序、插入排序、希尔排序是不稳定的排序算法。稳定性指的是相等的元素在排序过程中不会改变它们的先后顺序。

posted @ 2024-09-12 00:02  Abufan  阅读(16)  评论(0)    收藏  举报