十大排序算法(java)

十大排序算法(java)

img

冒泡排序

比较相邻的元素。如果第一个比第二个大,就交换他们两个

img

**for** (**int** i = 1; i < arr.length; i++) {
*// 设定一个标记,若为true,则表示此次循环没有进行交换,也就是待排序列已经有序,排序已经完成。*
**boolean** flag = **true**;

**for** (**int** j = 0; j < arr.length - i; j++) {
**if** (arr[j] > arr[j + 1]) {
**int** tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;

flag = **false**;
}
}

**if** (flag) {
**break**;
}
}
**return** arr;

选择排序

在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。

img

*// 总共要经过 N-1 轮比较*
**for** (**int** i = 0; i < arr.length - 1; i++) {
**int** min = i;

*// 每轮需要比较的次数 N-i*
**for** (**int** j = i + 1; j < arr.length; j++) {
**if** (arr[j] < arr[min]) {
*// 记录目前能找到的最小值元素的下标*
min = j;
}
}

*// 将找到的最小值和i位置所在的值进行交换*
**if** (i != min) {
**int** tmp = arr[i];
arr[i] = arr[min];
arr[min] = tmp;
}

}
**return** arr;

插入排序

只要打过扑克牌的人都应该能够秒懂——将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)

img

*// 对 arr 进行拷贝,不改变参数内容*
**int**[] arr = Arrays.copyOf(sourceArray, sourceArray.length);

*// 从下标为1的元素开始选择合适的位置插入,因为下标为0的只有一个元素,默认是有序的*
**for** (**int** i = 1; i < arr.length; i++) {

*// 记录要插入的数据*
**int** tmp = arr[i];

*// 从已经排序的序列最右边的开始比较,找到比其小的数*
**int** j = i;
**while** (j > 0 && tmp < arr[j - 1]) {
arr[j] = arr[j - 1];
j--;
}

*// 存在比其小的数,插入*
**if** (j != i) {
arr[j] = tmp;
}

}
**return** arr;

希尔排序

递减增量排序算法,插入排序的一种更高效的改进版本。

希尔排序是基于插入排序的以下两点性质而提出改进方法的:

  • 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率;

  • 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位;

    希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录"基本有序"时,再对全体记录进行依次直接插入排序。

    img

**int** gap = 1;
**while** (gap < arr.length) {
gap = gap * 3 + 1;
}

**while** (gap > 0) {
**for** (**int** i = gap; i < arr.length; i++) {
**int** tmp = arr[i];
**int** j = i - gap;
**while** (j >= 0 && arr[j] > tmp) {
arr[j + gap] = arr[j];
j -= gap;
}
arr[j + gap] = tmp;
}
gap = (**int**) Math.floor(gap / 3);
}

**return** arr;

归并排序

该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

  1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
  2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置;
  3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
  4. 重复步骤 3 直到某一指针达到序列尾;
  5. 将另一序列剩下的所有元素直接复制到合并序列尾

img

*// 对 arr 进行拷贝,不改变参数内容*
**int**[] arr = Arrays.copyOf(sourceArray, sourceArray.length);

**if** (arr.length < 2) {
**return** arr;
}
**int** middle = (**int**) Math.floor(arr.length / 2);

**int**[] left = Arrays.copyOfRange(arr, 0, middle);
**int**[] right = Arrays.copyOfRange(arr, middle, arr.length);

**return** merge(sort(left), sort(right));
}

**protected** **int**[] merge(**int**[] left, **int**[] right) {
**int**[] result = **new** **int**[left.length + right.length];
**int** i = 0;
**while** (left.length > 0 && right.length > 0) {
**if** (left[0] <= right[0]) {
result[i++] = left[0];
left = Arrays.copyOfRange(left, 1, left.length);
} **else** {
result[i++] = right[0];
right = Arrays.copyOfRange(right, 1, right.length);
}
}

**while** (left.length > 0) {
result[i++] = left[0];
left = Arrays.copyOfRange(left, 1, left.length);
}

**while** (right.length > 0) {
result[i++] = right[0];
right = Arrays.copyOfRange(right, 1, right.length);
}

**return** result;

快速排序

  1. 从数列中挑出一个元素,称为 “基准”(pivot);

  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;

  3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;

    img

*// 对 arr 进行拷贝,不改变参数内容*
**int**[] arr = Arrays.copyOf(sourceArray, sourceArray.length);

**return** quickSort(arr, 0, arr.length - 1);
}

**private** **int**[] quickSort(**int**[] arr, **int** left, **int** right) {
**if** (left < right) {
**int** partitionIndex = partition(arr, left, right);
quickSort(arr, left, partitionIndex - 1);
quickSort(arr, partitionIndex + 1, right);
}
**return** arr;
}

**private** **int** partition(**int**[] arr, **int** left, **int** right) {
*// 设定基准值(pivot)*
**int** pivot = left;
**int** index = pivot + 1;
**for** (**int** i = index; i <= right; i++) {
**if** (arr[i] < arr[pivot]) {
swap(arr, i, index);
index++;
}
}
swap(arr, pivot, index - 1);
**return** index - 1;
}

**private** **void** swap(**int**[] arr, **int** i, **int** j) {
**int** temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;

堆排序

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。分为两种方法:

  1. 大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;
  2. 小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列;

堆排序的平均时间复杂度为 Ο(nlogn)

  1. 创建一个堆 H[0……n-1];
  2. 把堆首(最大值)和堆尾互换;
  3. 把堆的尺寸缩小 1,并调用 shift_down(0),目的是把新的数组顶端数据调整到相应位置;
  4. 重复步骤 2,直到堆的尺寸为 1。

img

*// 对 arr 进行拷贝,不改变参数内容*
**int**[] arr = Arrays.copyOf(sourceArray, sourceArray.length);

**int** len = arr.length;

buildMaxHeap(arr, len);

**for** (**int** i = len - 1; i > 0; i--) {
swap(arr, 0, i);
len--;
heapify(arr, 0, len);
}
**return** arr;
}

**private** **void** buildMaxHeap(**int**[] arr, **int** len) {
**for** (**int** i = (**int**) Math.floor(len / 2); i >= 0; i--) {
heapify(arr, i, len);
}
}

**private** **void** heapify(**int**[] arr, **int** i, **int** len) {
**int** left = 2 * i + 1;
**int** right = 2 * i + 2;
**int** largest = i;

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

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

**if** (largest != i) {
swap(arr, i, largest);
heapify(arr, largest, len);
}
}

**private** **void** swap(**int**[] arr, **int** i, **int** j) {
**int** temp = arr[i];
arr[i] = arr[j];
`arr[j] = temp;

计数排序

待续

桶排序

待续

基数排序

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值