分类 | 时间复杂度 | 空间复杂度 | 稳定性 | |||
最好 | 平均 | 最坏 | ||||
插入排序 | 直接插入排序 | O(n) | O(n2) | O(n2) | O(1) | 稳定 |
希尔排序 | O(n) | O(n1-2) | O(n2) | O(1) | 不稳定 | |
选择排序 | 简单选择排序 | O(n2) | O(n2) | O(n2) | O(1) | 不稳定 |
堆排序 | O(nlog2n) | O(nlog2n) | O(nlog2n) | O(1) | 不稳定 | |
交换排序 | 冒泡排序 | O(n) | O(n2) | O(n2) | O(1) | 稳定 |
快速排序 | O(nlog2n) | O(nlog2n) | O(n2) | O(nlog2n) | 不稳定 | |
归并排序 | O(nlog2n) | O(nlog2n) | O(nlog2n) | O(n) | 稳定 | |
基数排序 | O(d*(n+r)),d是长度, r是基数,n是关键字个数 | O(d*(n+r)) | O(d*(n+r)) | O(r+n) | 稳定 |
直接插入排序
思想:每次将待排序数组的第一个最小(大)值插入到已排序数组中
public void insertSort(int[] arr) {
int temp, j;
for (int i = 1; i < arr.length; i++) {
temp = arr[i]; // 记录待排序数组的 第一个数据
j = i - 1;
while (j >= 0 && arr[j] > temp) { //逐个向前检查
arr[j+1] = arr[j];
j--;
}
arr[j + 1] = temp; // 插入到合适的位置
}
}
希尔排序
思想:将数组按照增量gap分组,每组组内使用直接插入排序,再逐步缩小增量,直到增量==1为止
public void shellSort(int[] arr) {
int gap = arr.length;
while(gap>1){
gap=gap/3+1;
shell(arr,gap);
}
}
// 直接插入排序中相当于gap==1
public void shell(int[] arr, int gap) {
int temp,j;
for(int i=gap; i<arr.length; i++){
temp = arr[i];
j = i-gap;
while(j>=0 && arr[j]>temp){
arr[j+gap] = arr[j];
j-=gap;
}
arr[j+gap] = temp;
}
}
简单选择排序
思路:每次遍历待排序数组,将其中的最小值放到数组第一位
public void selectSort(int[] arr) {
for (int i = 0; i < arr.length; i++) {
for(int j=i+1; j<arr.length; j++){
if(arr[i]>arr[j]){
swap(arr,i,j);
}
}
}
}
堆排序
思路:
public static void heapSort(int[] arr) {
// p 指向父节点,从最后一个 非叶子节点 调整到根节点
for (int p = arr.length / 2 - 1; p >= 0; p--) {
buildTree(arr, p, arr.length);
}
int length = arr.length;
while (length > 1) {
swap(arr, 0, length - 1);
length--;
buildTree(arr, 0, length);
}
}
public static void buildTree(int[] arr, int p, int length) {
for (int i = 2 * p + 1; i < length; i = 2 * i + 1) {
// 如果右子树大于左子树,则用右子树进行比较
if (i + 1 < length && arr[i] < arr[i + 1]) i++;
if (arr[p] < arr[i]) {
swap(arr, i, p);
p = i;
} else {
break;
}
}
}
冒泡排序
思路:在待排序数组中,通过交换,每一次遍历使最大的数放到数组中的最后一位
public void bubbleSort(int[] arr) {
for (int i = 1; i < arr.length; i++) {
for(int j = 0; j<arr.length-i; j++){
if(arr[j]>arr[j+1]){
swap(arr,j,j+1);
}
}
}
}
快速排序
思路:选择一个基准(一般为第一个或者最后一个数),在经过一次遍历后,数组左边所有数小于这个基准,右边所有数大于这个基准,但是都是无序的,再通过递归排序左右两个数组。
public void quickSort(int[] arr,int start, int end) {
if(start>=end)
return;
int temp = arr[start]; //基准
int left = start;
int right = end;
while(left<right){ // 将小于temp的数放在左边,大于temp的数放在右边
while(left<right && arr[right]>=temp) right--; //找到右边第一个小于temp的数
while(left<right && arr[left]<=temp) left++; //找到左边第一个大于temp的数
if(left<right){
swap(arr,left,right);
}
}
arr[start] = arr[left];
arr[left] = temp; // 将arr[left]与arr[start]交换位置,
quickSort(arr, start, left-1);
quickSort(arr, left+1, end);
}
归并排序
思路:先把数组拆分为若干个子序列,并将子序列排序后再合并为完整的序列
将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。
public void mergeSort(int[] arr, int start, int end) {
if (start >= end)
return;
int mid = start + (end - start) / 2;
mergeSort(arr, start, mid);
mergeSort(arr, mid + 1, end); // 先进行拆分
merge(arr, start, mid, end); // 合并
}
public void merge(int[] arr, int start, int mid, int end){
int[] temp = new int[end - start + 1]; //创建一个空数组用于排序
int left = start;
int right = mid + 1;
int index = 0;
// 将数组分为左右两部分,并逐个比较,按顺序放入temp数组中
while (left <= mid && right <= end) {
if (arr[left] < arr[right]) {
temp[index++] = arr[left++];
} else {
temp[index++] = arr[right++];
}
}
// 当左半部分或者右半部分全放入temp中后,检查左右两部分是否还仍有未放入temp的数
while (left <= mid) {
temp[index++] = arr[left++];
}
while (right <= end) {
temp[index++] = arr[right++];
}
for (int i = 0; i < temp.length; i++) {
arr[i + start] = temp[i]; // 将temp返回至arr
}
}
基数排序
思路:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。
public void baseSort(int[] arr) {
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
max = Math.max(max, arr[i]);
}
int maxLength = (max + "").length(); //计算数组中最大数字的位数
int[][] bucket = new int[10][arr.length]; //存放数字
int[] elementCount = new int[10]; //计数
int n = 1;
for (int i = 0; i < maxLength; i++) {
for (int value : arr) {
int element = value/n%10;
bucket[element][elementCount[element]]=value;
elementCount[element]++;
}
int index = 0;
for (int j = 0; j < elementCount.length; j++) {
if(elementCount[j]!=0){
for (int k = 0; k < elementCount[j]; k++) {
arr[index++] = bucket[j][k]; //将桶中的数据放回arr
}
}
elementCount[j]=0; //计数器全归0
}
n*=10;
}
}