‌使用ArkTS完成经典排序算法(插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序.) 原创

中杯可乐多加冰
发布于 2025-3-26 20:41
2847浏览
1收藏

在万物互联的智能时代,华为HarmonyOS作为面向全场景的分布式操作系统,正在重塑应用开发的范式。ArkTS是华为基于TypeScript扩展的声明式开发语言,它继承了TypeScript的所有特性,同时针对HarmonyOS进行了深度优化。作为JavaScript的超集,ArkTS不仅保留了动态语言的灵活性,还通过静态类型系统大大提升了代码的可靠性和可维护性。

‌使用ArkTS完成经典排序算法(插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序.)-鸿蒙开发者社区

而算法是程序开发中不可或缺的一部分。排序算法作为最基本、最常用的算法之一,在程序开发中起到了至关重要的作用。本文将使用ArkTS实现十大经典排序算法,帮助开发者在HarmonyOS应用中高效处理数据。

一、冒泡排序

冒泡排序是一种基本的排序算法,其思路是比较相邻元素的大小,如果逆序则交换,一轮结束后将最大元素“冒泡”到数列的末尾。这个过程像冒泡一样,因此被称为冒泡排序。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

// 冒泡排序ArkTS实现
function bubbleSort(arr: number[]): number[] {
  for (let i = 0; i < arr.length - 1; i++) {
    for (let j = 0; j < arr.length - 1 - i; j++) {
      if (arr[j] > arr[j + 1]) {
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]; // ES6解构交换
      }
    }
  }
  return arr;
}

// 可视化组件
@Component
struct BubbleSortDemo {
  @State data: number[] = [5, 3, 8, 4, 2]
  @State sortedData: number[] = []

  build() {
    Column() {
      Text('原始数组: ' + this.data.toString())
      Button('执行冒泡排序')
        .onClick(() => {
          this.sortedData = bubbleSort([...this.data])
        })
      Text('排序结果: ' + this.sortedData.toString())
    }
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.

时间复杂度:

  • 最好情况:已经有序,只需要进行一次比较,时间复杂度为O(n)。
  • 最坏情况:完全逆序,需要进行n轮比较,时间复杂度为O(n^2)。
  • 平均情况:时间复杂度也为O(n^2)。

二、选择排序

选择排序是一种简单直观的排序算法,其思想是每次从待排序的数列中选择最小(或最大)的元素,放到已排序数列的末尾(或开头),直到整个数列有序。

function insertionSort(arr: number[]): number[] {
  const array = arr.slice();
  for (let i = 1; i < array.length; i++) {
    const current = array[i];
    let j = i - 1;
    while (j >= 0 && array[j] > current) {
      array[j + 1] = array[j];
      j--;
    }
    array[j + 1] = current;
  }
  return array;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

时间复杂度:

  • 最好情况:O(n^2)。
  • 最坏情况:O(n^2)。
  • 平均情况:O(n^2)。

三、插入排序

插入排序是一种简单直观的排序算法,其基本思想是将待排序序列分为两部分,一部分已经排好序,另一部分待排序,然后将待排序部分的元素依次插入到已排序部分的适当位置,使得插入后仍然有序。

function selectionSort(arr: number[]): number[] {
  const array = arr.slice();
  for (let i = 0; i < array.length - 1; i++) {
    let minIndex = i;
    for (let j = i + 1; j < array.length; j++) {
      if (array[j] < array[minIndex]) {
        minIndex = j;
      }
    }
    [array[i], array[minIndex]] = [array[minIndex], array[i]];
  }
  return array;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

四、归并排序

归并排序是一种经典的分治算法,它的基本思想是将待排序的数组划分为两个子数组,分别对这两个子数组进行排序,然后将排序后的子数组合并成一个有序数组。具体来说,归并排序的步骤如下:

  1. 分解:将待排序的数组不断地二分,直到每个子数组只包含一个元素,即认为这些子数组已经有序。
  2. 合并:将已经有序的子数组两两合并,形成新的有序子数组。
  3. 重复步骤2,直到只剩下一个有序数组,即为最终排序结果。

简易写法:

function mergeSort(arr: number[]): number[] {
  if (arr.length <= 1) return arr.slice();
  
  const mid = Math.floor(arr.length / 2);
  const left = mergeSort(arr.slice(0, mid));
  const right = mergeSort(arr.slice(mid));
  return merge(left, right);
}
function merge(left: number[], right: number[]): number[] {
  let i = 0, j = 0;
  const result: number[] = [];
  while (i < left.length && j < right.length) {
    result.push(left[i] < right[j] ? left[i++] : right[j++]);
  }
  return result.concat(left.slice(i)).concat(right.slice(j));
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

归并排序的时间复杂度是O(nlogn),其中n是待排序数组的长度。虽然归并排序的时间复杂度比较稳定,但需要额外的空间来存储辅助数组,因此其空间复杂度是O(n)。

时间复杂度:假设数组长度为 n,需要进行 logn 次归并操作;每次归并操作需要 O(n) 的时间复杂度;

  • 最好情况:O(n)。
  • 最坏情况:O(nlogn)。
  • 平均情况:O(nlogn)。

五、快速排序

快速排序采用分治策略,首先选取一个基准元素,将数组划分为左右两部分:左边元素均小于基准,右边元素均大于基准,然后递归地对左右子数组重复此过程。通过双指针从两端扫描并交换不符合条件的元素,最终确保基准处于正确位置,实现整体有序。

function quickSort(arr: number[]): number[] {
  const array = arr.slice();
  quickSortHelper(array, 0, array.length - 1);
  return array;
}

// 快速排序辅助函数
function quickSortHelper(arr: number[], low: number, high: number): void {
  if (low < high) {
    const pi = partition(arr, low, high);
    quickSortHelper(arr, low, pi - 1);
    quickSortHelper(arr, pi + 1, high);
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

六、希尔排序

希尔排序是一种插入排序的变体,也称为缩小增量排序。其基本思想是将待排序的数组分成若干个子序列,对每个子序列进行插入排序,然后逐步缩小增量,直到增量为1。

具体来说,希尔排序的步骤如下:

  1. 选择一个增量序列:将待排序数组按照一定的间隔划分成若干个子序列,对每个子序列进行插入排序。这里的增量序列可以使用Hibbard增量序列,它的公式为2k12^k-1,其中k为增量的大小,从n/2、n/4、n/8等不断除以2,直到增量等于1为止。
  2. 对子序列进行插入排序:对每个子序列进行插入排序,将子序列中的数依次插入到前面已经排好序的序列中,使得插入后仍然有序。
  3. 逐步缩小增量:对于增量序列,逐步缩小增量,重复步骤2,直到增量为1。
function shellSort(arr: number[]): number[] {
  const array = arr.slice();
  let gap = Math.floor(array.length / 2);

  while (gap > 0) {
    for (let i = gap; i < array.length; i++) {
      const temp = array[i];
      let j = i;
      
      while (j >= gap && array[j - gap] > temp) {
        array[j] = array[j - gap];
        j -= gap;
      }
      
      array[j] = temp;
    }
    gap = Math.floor(gap / 2);
  }
  
  return array;
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.

七、堆排序

堆排序的实现过程主要分为两个步骤:

  1. 构建最大堆:将待排序的数组看作是完全二叉树的形式,从最后一个非叶子节点开始,依次对每个非叶子节点进行堆调整,使其成为最大堆的形式。具体做法是比较节点和它的两个子节点之间的大小,将较大的子节点调整到父节点的位置上,然后递归地对调整过后的子节点进行堆调整。
  2. 堆排序:从最大堆中取出根节点(即数组的第一个元素),将其与最后一个元素交换位置,然后对剩余的节点重新进行堆调整,以确保剩余节点仍然构成最大堆。重复这个过程,直到所有元素都被取出并排序。

堆排序相较于其他排序算法的优势在于,它是一种原地排序算法,只需要一个额外的空间来存放根节点的值,没有浪费的空间。同时,堆排序还具有稳定的时间复杂度和稳定的排序结果。不过,需要注意的是,堆排序对于小规模的数据排序并不是特别高效,适用于大规模数据的排序。

// 堆排序
function heapSort(arr: number[]): number[] {
  const array = arr.slice();
  let n = array.length;

  // 构建最大堆
  for (let i = Math.floor(n / 2) - 1; i >= 0; i--) {
    heapify(array, n, i);
  }

  // 逐个提取元素
  for (let i = n - 1; i > 0; i--) {
    [array[0], array[i]] = [array[i], array[0]];
    heapify(array, i, 0);
  }
  return array;
}

// 堆化函数
function heapify(arr: number[], n: number, i: number): void {
  let largest = i;
  const left = 2 * i + 1;
  const right = 2 * i + 2;

  if (left < n && arr[left] > arr[largest]) {
    largest = left;
  }

  if (right < n && arr[right] > arr[largest]) {
    largest = right;
  }

  if (largest !== i) {
    [arr[i], arr[largest]] = [arr[largest], arr[i]];
    heapify(arr, n, largest);
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.

通过ArkTS实现这些经典排序算法,开发者可以在HarmonyOS应用中高效处理各种数据排序需求。ArkTS的类型系统和现代语法使得算法实现既安全又简洁,欢迎大家点赞评论!

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
收藏 1
回复
举报
1


回复