排序算法分为: 三大基本排序---冒泡排序,选择排序,插入排序
高级排序---------希尔排序,快速排序,归并排序,堆排序
非比较排序------基数排序
参考资料:https://www.runoob.com/w3cnote/sort-algorithm-summary.html
1.冒泡排序
基本思想:两个数比较大小,较大的数下沉,较小的数冒起来,依次把最小,次小的排在前面,最后完成排序
平均时间复杂度:O(n2)
public class BubbleSort {
public static void sort(int[] arr) {
int temp;//临时变量
for (int i = 0; i < arr.length; i++) {
for (int j = arr.length - 1; j > i; j--) {
if (arr[j] < arr[j - 1]) {
temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
}
}
}
}
public static void qrSort(int[] arr) {
int temp;//临时变量
boolean flag;//标志位
for (int i = 0; i < arr.length; i++) {
flag = true;
//只有交换时把flag设置为false,不交换证明后面的数组是有序的,直接跳出循环
for (int j = arr.length - 1; j > i; j--) {
if (arr[j] < arr[j - 1]) {
temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
flag = false;
}
}
//后面数组有序跳出循环
if (false) {
break;
}
}
}
}
2.选择排序
基本思想:
在长度为N的无序数组中,第一次遍历n-1个数,找到最小的数值与第一个元素交换;
第二次遍历n-2个数,找到最小的数值与第二个元素交换
平均时间复杂度:O(n2)
public class SelctionSort {
public static void sort(int[] arr) {
int temp;//临时变量
int index;//临时位置
for (int i = 0; i < arr.length; i++) {
index = i;
for (int j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[index]) {
index = j;
}
}
//判断交换
if (i != index) {
temp = arr[i];
arr[i] = arr[index];
arr[index] = temp;
}
}
}
}
3.插入排序
基本思想:
在要排序的一组数中,假定前n-1个数已经排好序,现在将第n个数插到前面的有序数列中,使得这n个数也是排好顺序的。如此反复循环,直到全部排好顺序。
平均时间复杂度:O(n2)
public class InsertionSort {
public static void sort(int[] arr) {
int temp;//临时变量
for (int i = 0; i < arr.length-1; i++) {
for (int j = i + 1; j > 0; j--) {
if (arr[j] < arr[j - 1]) {
temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
} else {//不需要交换
break;
}
}
}
}
}
4.希尔排序
前言:
数据序列1: 13-17-20-42-28 利用插入排序,13-17-20-28-42. Number of swap:1;
数据序列2: 13-17-20-42-14 利用插入排序,13-14-17-20-42. Number of swap:3;
如果数据序列基本有序,使用插入排序会更加高效。
基本思想:
在要排序的一组数中,根据某一增量分为若干子序列,并对子序列分别进行插入排序。
然后逐渐将增量减小,并重复上述过程。直至增量为1,此时数据序列基本有序,最后进行插入排序。
public class ShellSort {
/**
* 希尔排序就是对于数组进行分组排序
*/
public static void sort(int[] arr) {
int incre = arr.length;//表示有多少组
int temp;//临时变量
while (incre > 1) {
incre /= 2;//每次分组,每个子分组扩大,排序
for (int k = 0; k < incre; k++) {//对于每一组进行遍历排序
//使用插入排序对子数组进行排序
for (int i = k + incre; i < arr.length; i += incre) {
for (int j = i; j > k; j -= incre) {
if (arr[j] < arr[j - incre]) {
temp = arr[j];
arr[j] = arr[j - incre];
arr[j - incre] = temp;
} else {
break;
}
}
}
}
}
}
}
5.快速排序
基本思想:(分治)
辅助理解:挖坑填数
数组:72 - 6 - 57 - 88 - 60 - 42 - 83 - 73 - 48 - 85
0 1 2 3 4 5 6 7 8 9
数组:48 - 6 - 57 - 88 - 60 - 42 - 83 - 73 - 88 - 85
0 1 2 3 4 5 6 7 8 9
数组:48 - 6 - 57 - 42 - 60 - 72 - 83 - 73 - 88 - 85
0 1 2 3 4 5 6 7 8 9
public class QuickSort {
public static void sort(int[] arr, int start, int end) {
if (start >= end) {
return;
}
int i = start;
int j = end;
int key = arr[i];
while (i < j) {
while (i < j && key <= arr[j]) {
j--;
}
if (i < j) {
arr[i] = arr[j];
i++;
}
while (i < j && key > arr[i]) {
i++;
}
if (i < j) {
arr[j] = arr[i];
j--;
}
}
//i == j
arr[i] = key;
sort(arr, start, i-1);
sort(arr, i+1, end);
}
}
6.归并排序
基本思想: 可以将A,B组各自再分成2组。依次类推,当分出来的小组只有1个数据时,可以认为这个小组组内已经达到了有序,然后再合并相邻的2个小组就可以了。这样通过先递归的分解数列,再合并数列就完成了归并排序。
平均时间复杂度:O(NlogN)
public class MergeSort {
public static void sort(int[] arr, int start, int end, int[] temp) {
if (start < end) {
int middle = (start + end) / 2;
sort(arr, start, middle, temp);
sort(arr, middle + 1, end, temp);
merageArray(arr, start, middle, end, temp);
}
}
//合并数组
public static void merageArray(int[] arr, int start, int middle, int end, int[] temp) {
int i = start;
int j = middle;
int k = middle + 1;
int l = end;
int m = start;
while (i <= j && k <= l) {
if (arr[i] < arr[k]) {
temp[m++] = arr[i++];
} else {
temp[m++] = arr[k++];
}
}
while (i <= j) {
temp[m++] = arr[i++];
}
while (k <= l) {
temp[m++] = arr[k++];
}
for (int ii = start; ii <= end; ii++) {
arr[ii] = temp[ii];
}
}
}
7.堆排序
基本思想:建立二叉树,其中i的子节点为2*i+1,和2*i+2。然后建立最小(大)树,可以保证每次最小(大)的值在0位置,取出放置数组后端,最后调整二叉树的长度,重新恢复堆,重复操作获取有序的数组,最小树构建有大到小的数组
平均时间复杂度:O(NlogN)
public class HeapSort {
//构建最小树
public static void buildMinHeap(int[] arr, int length) {
for (int i = (length - 1) / 2; i >= 0; i--) {
minHeapFixdown(arr, i, length);
}
}
//最小树,大数下沉
public static void minHeapFixdown(int[] arr, int start, int end) {
int i = start;
int j = 2 * i + 1;
int temp;
while (j < end) {
if ((j + 1) < end && arr[j] > arr[j + 1]) {
j++;
}
if (arr[j] >= arr[i]) {
break;
}
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
i = j;
j = 2 * j + 1;
}
}
public static void sort(int[] arr) {
buildMinHeap(arr, arr.length);
int temp;
for (int i = arr.length - 1; i > 0; i--) {
temp = arr[i];
arr[i] = arr[0];
arr[0] = temp;
minHeapFixdown(arr, 0, i);
}
}
}
8.基数排序
BinSort想法非常简单,首先创建数组A[MaxValue];然后将每个数放到相应的位置上(例如17放在下标17的数组位置);最后遍历数组,即为排序后的结果
基本思想: 基数排序是在BinSort的基础上,通过基数的限制来减少空间的开销。
过程:先判断最大数的位数,有个位数直到最大位数,依次进行分组,在对应的数组,由于是对基数分组,分好后依次取出就是相应位数的排序,所以由个位数到最大位数循环操作后就得到有序序列。如下图
public class RadixSort {
public static void sort(int[] arr, int radix, int n, int k, int[] temp, int[] cnt) {
//arr:原数组
//temp:临时数组
//n:序列的数字个数
//k:最大的位数2
//radix:基数10
//cnt:存储bin[i]的个数,基数对应数组的数量
for (int i = 0, rtok = 1; i < k; i++, rtok *= radix) {
//初始化cnt数组
for (int j = 0; j < radix; j++) {
cnt[j] = 0;
}
//计算每一个数组的大小
for (int j = 0; j < n; j++) {
cnt[(arr[j] / rtok) % radix]++;
}
/**
* 每一个cnt数组的大小等于前面数组的和加上本数组的大小
* 这样是为了方便计算对于数的位置,等于直接在temp中划分出对应的位置放置数
* 直接把temp划分为对应位置,例如cnt[j]的数组划分了为 cnt[j-1]-1 到 cnt[j]-1 之间
*/
for (int j = 1; j < radix; j++) {
cnt[j] += cnt[j - 1];
}
for (int j = 0; j < n; j++) {
cnt[(arr[j] / rtok) % radix]--;
temp[cnt[(arr[j] / rtok) % radix]] = arr[j];
}
//放置原数组
for (int j = 0; j < n; j++) {
arr[j] = temp[j];
}
}
}
}