冒泡排序
类似暴力破解,1 – n 个,每个都比较一次。完成排序
public void sort(int[] arr) {
int len = arr.length;
for (int i = 0; i < len; i++) {
for (int j = i + 1; j < len - 1; j++) {
if (arr[i] > arr[j]) {
SwapUtil.swap(arr, i, j);
}
}
}
}
选择排序
[ 排序完毕 | 未排序] 每次从未排序的找一个最小的放入到排序完毕的后边
public void sort(int[] arr) {
int len = arr.length;
for (int i = 0; i < len; i++) {
int index = findMinIndex(arr, i);
if (index != -1) {
SwapUtil.swap(arr, i, index);
}
}
}
public int findMinIndex(int[] arr, int begin) {
int len = arr.length;
int index = -1, elem = arr[begin];
for (; begin < len; begin++) {
if (arr[begin] < elem) {
index = begin;
elem = arr[begin];
}
}
return index;
}
堆排序
堆排序
先进行堆的构建,再进行堆的调整
@Override
public void sort(int[] arr) {
int len = arr.length;
sort(arr, len);
}
private void sort(int[] arr, int len) {
buildMaxHeap(arr, len);
adjust(arr, len);
}
private void adjust(int[] arr, int len) {
for (int i = len - 1; i > 0; i--) {
SwapUtil.swap(arr, 0, i);
adjustHeap(arr, 0, i);
}
}
private void buildMaxHeap(int[] arr, int len) {
// 这里索引从 0 开始,所以最后一个非叶子子节点 array.length / 2 - 1;
for (int i = len / BUILD_HEAP_SEPARATED - 1; i >= 0; i--) {
adjustHeap(arr, i, len);
}
System.out.println("build heap : " + Arrays.toString(arr));
}
private void adjustHeap(int[] arr, int i, int length) {
// 先把当前元素取出来,因为当前元素可能要一直移动
int temp = arr[i];
// 从左孩子开始遍历 ( 2i + 1)
for (int k = 2 * i + 1; k < length; k = 2 * k + 1) {
// 若右孩子存在,且右孩子大于左孩子
if (k + 1 < length && arr[k] < arr[k + 1]) {
// 转移到右孩子
k++;
}
// 如果发现结点(左右子结点)大于根结点,则进行值的交换
if (arr[k] > temp) {
SwapUtil.swap(arr, i, k);
// 如果子节点更换了,则以子节点为根的子树会受到影响,
// 所以,循环对子节点所在的树继续进行判断
i = k;
} else {
//不用交换,直接终止循环
break;
}
}
}
希尔排序
这里采用数组长度一半作为希尔增量进行排序,每次减少一半,知道增量为1.排序完毕。
@Override
public void sort(int[] arr) {
int step = arr.length / 2;
for ( ; step > 0; step /= 2) {
for (int i = step; i < arr.length; i++) {
int value = arr[i];
int j;
// 跳跃的插入, 因为增量的存在,所以,后移时,是当前增量后移
for (j = i - step; j >= 0 && arr[j] > value; j -= step) {
arr[j + step] = arr[j];
}
arr[j + step] = value;
}
}
}
插入排序
类似于选择排序,分为【排序 | 未排序区域】每次从未排序区域选取一个,再排序区域寻找位置,然后后移交换。
@Override
public void sort(int[] arr) {
int len = arr.length;
for (int i = 1; i < len; i++) {
int elem = arr[i];
int index = getIndex(arr, i, elem);
if (index != i) {
retreat(arr, index, i);
arr[index] = elem;
}
}
}
/**
* 获取插入排序所在索引
* @param arr 数组
* @param limit 已排序区间上界
* @param elem 待排序元素
* @return 要插入的数组
*/
private int getIndex(int[] arr, int limit, int elem) {
for (int i = 0; i < limit; i++) {
if (elem < arr[i]) {
return i;
}
}
return limit;
}
/**
* 将数组内一段元素后移
* @param arr 数组
* @param begin 区间下界
* @param end 区间上界
*/
private void retreat(int[] arr, int begin, int end) {
while(end > begin) {
arr[end] = arr[end - 1];
end--;
}
}
二路归并排序
@Override
public void sort(int[] arr) {
mergeSort(arr, 0, arr.length - 1);
}
public void mergeSort(int[] arr, int left, int right) {
if (left < right) {
int mid = (left + right) / 2;
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, mid, right);
}
}
public void merge(int[] arr, int left, int mid, int right) {
int[] temp = new int[arr.length];
int leftIndex = left, rightIndex = mid + 1, tempIndex = left;
while (leftIndex <= mid && rightIndex <= right) {
if (arr[leftIndex] < arr[rightIndex]) {
temp[tempIndex++] = arr[leftIndex++];
} else {
temp[tempIndex++] = arr[rightIndex++];
}
}
while (leftIndex <= mid) {
temp[tempIndex++] = arr[leftIndex++];
}
while(rightIndex <= right) {
temp[tempIndex++] = arr[rightIndex++];
}
// 将归并结果归坏到原数组中
while (left <= right) {
arr[left] = temp[left++];
}
}
快速排序
设数组第一个元素为基准,
第一步:数组中所有元素,小于 基准 放到左边,大于 基准 放到右边,此时数组分为两部分,对于基准来说已经处于它应处的位置
第二步,对左右两半数组继续执行第一步,递归完毕,数组有序
时间复杂度: O(n*log2n) – 空间复杂度: good: O(log2n) – bad: O(n)
@Override
public void sort(int[] arr) {
int len = arr.length;
sort(arr, 0, len - 1);
}
private void sort(int[] arr, int left, int right) {
if (left < right) {
int mid = partition(arr, left, right);
sort(arr, left, mid - 1);
sort(arr, mid + 1, right);
}
}
private int partition(int[] arr, int left, int right) {
int sentry = arr[left];
while (left < right) {
while (left < right && arr[right] >= sentry) {
right--;
}
arr[left] = arr[right];
while(left < right && arr[left] <= sentry) {
left++;
}
arr[right] = arr[left];
}
arr[left] = sentry;
return left;
}
排序比较
| 排序方法 | 最好情况 | 最坏情况 | 平均情况 | 空间复杂度 | 稳定性 |
|---|---|---|---|---|---|
| 直接插入排序 | O(n) | O(n^2) | O(n^2) | O(1) | 稳定 |
| 折半插入排序 | O(nlong2n) | O(n^2) | O(n^2) | O(1) | 稳定 |
| 希尔排序 | O(n^1.3) | O(1) | 不稳定 | ||
| 冒泡排序 | O(n) | O(n^2) | O(n^2) | O(1) | 稳定 |
| 简单选择排序 | O(n) | O(n^2) | O(n^2) | O(1) | 不稳定 |
| 快速排序 | O(nlog2n) | O(n^2) | O(nlog2n) | O(nlog2n) | 不稳定 |
| 堆排序 | O(nlog2n) | O(nlog2n) | O(nlog2n) | O(1) | 不稳定 |
| 归并排序 | O(nlog2n) | O(nlog2n) | O(nlog2n) | O(n) | 稳定 |
| 基数排序 | O(d(n+rd)) | O(d(n+rd)) | O(d(n+rd)) | O(n+rd) | 稳定 |
125jz网原创文章。发布者:江山如画,转载请注明出处:http://www.125jz.com/8811.html
微信扫一扫
支付宝扫一扫